1#!/usr/bin/env python 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# A tool that can read diagnostic events from a Diagnostic JSON document 19# and forward them to Vehicle HAL via vhal_emulator 20# Use thusly: 21# $ ./diagnostic_injector.py <path/to/diagnostic.json> 22 23import argparse 24import json 25import sys 26import time 27 28import vhal_consts_2_0 as c 29 30# vhal_emulator depends on a custom Python package that requires installation 31# give user guidance should the import fail 32try: 33 from vhal_emulator import Vhal 34except ImportError as e: 35 isProtobuf = False 36 pipTool = "pip%s" % ("3" if sys.version_info > (3,0) else "") 37 if hasattr(e, 'name'): 38 if e.name == 'google': isProtobuf = True 39 elif hasattr(e, 'message'): 40 if e.message.endswith('symbol_database'): 41 isProtobuf = True 42 if isProtobuf: 43 print('could not find protobuf.') 44 print('protobuf can be installed via "sudo %s install --upgrade protobuf"' % pipTool) 45 sys.exit(1) 46 else: 47 raise e 48 49from diagnostic_builder import DiagnosticEventBuilder 50 51class DiagnosticHalWrapper(object): 52 def __init__(self, device): 53 self.vhal = Vhal(c.vhal_types_2_0, device) 54 self.liveFrameConfig = self.chat( 55 lambda hal: hal.getConfig(c.VEHICLEPROPERTY_OBD2_LIVE_FRAME)) 56 self.freezeFrameConfig = self.chat( 57 lambda hal: hal.getConfig(c.VEHICLEPROPERTY_OBD2_FREEZE_FRAME)) 58 self.eventTypeData = { 59 'live' : { 60 'builder' : lambda: DiagnosticEventBuilder(self.liveFrameConfig), 61 'property' : c.VEHICLEPROPERTY_OBD2_LIVE_FRAME 62 }, 63 'freeze' : { 64 'builder' : lambda: DiagnosticEventBuilder(self.freezeFrameConfig), 65 'property' : c.VEHICLEPROPERTY_OBD2_FREEZE_FRAME 66 }, 67 } 68 69 def chat(self, request): 70 request(self.vhal) 71 return self.vhal.rxMsg() 72 73 def inject(self, file): 74 data = json.load(open(file)) 75 lastTimestamp = 0 76 for event in data: 77 currentTimestamp = event['timestamp'] 78 # time travel isn't supported (yet) 79 assert currentTimestamp >= lastTimestamp 80 # wait the delta between this event and the previous one 81 # before sending it out; but on the first event, send now 82 # or we'd wait for a long long long time 83 if lastTimestamp != 0: 84 # also, timestamps are in nanoseconds, but sleep() uses seconds 85 time.sleep((currentTimestamp-lastTimestamp)/1000000000) 86 lastTimestamp = currentTimestamp 87 # now build the event 88 eventType = event['type'].encode('utf-8') 89 eventTypeData = self.eventTypeData[eventType] 90 builder = eventTypeData['builder']() 91 builder.setStringValue(event.get('stringValue', '')) 92 for intValue in event['intValues']: 93 builder.addIntSensor(intValue['id'], intValue['value']) 94 for floatValue in event['floatValues']: 95 builder.addFloatSensor(floatValue['id'], floatValue['value']) 96 builtEvent = builder.build() 97 print ("Sending %s %s..." % (eventType, builtEvent)), 98 # and send it 99 status = self.chat( 100 lambda hal: 101 hal.setProperty(eventTypeData['property'], 102 0, 103 builtEvent)).status 104 if status == 0: 105 print("ok!") 106 else: 107 print("fail: %s" % status) 108 109parser = argparse.ArgumentParser(description='Diagnostic Events Injector') 110parser.add_argument('jsondoc', nargs='+') 111parser.add_argument('-s', action='store', dest='deviceid', default=None) 112 113args = parser.parse_args() 114 115halWrapper = DiagnosticHalWrapper(device=args.deviceid) 116 117for arg in args.jsondoc: 118 print("Injecting %s" % arg) 119 halWrapper.inject(arg) 120