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 simple GUI to remotely actuate the Vehicle HAL via the eumalator 19 20import argparse 21import sys 22from threading import Thread 23from PyQt4.QtCore import * 24from PyQt4.QtGui import * 25 26import VehicleHalProto_pb2 27from vhal_emulator import Vhal 28import vhal_consts_2_0 as c 29 30 31# Define a simple thread that receives messages from a vhal object (v) and prints them 32def rxThread(v): 33 while(1): 34 msg = v.rxMsg() 35 if (msg.msg_type == VehicleHalProto_pb2.SET_PROPERTY_RESP): 36 if msg.status == 0: 37 print "Success ("+str(msg.status)+")" 38 else: 39 print "Error ("+str(msg.status)+")" 40 else: 41 print msg; 42 43 44# Main window setup 45def window(): 46 app = QApplication(sys.argv) 47 widget = QWidget() 48 widget.setWindowTitle("VHal Driver") 49 widget.setGeometry(100,100,200,50) 50 topLevelLayout = QHBoxLayout() 51 widget.setLayout(topLevelLayout) 52 53 shiftLayout = QVBoxLayout() 54 topLevelLayout.addLayout(shiftLayout) 55 56 gearTitle = QLabel(widget) 57 gearTitle.setText("Gear Shift") 58 shiftLayout.addWidget(gearTitle); 59 60 gearDisplay = QLabel(widget) 61 shiftLayout.addWidget(gearDisplay); 62 63 slider = QSlider(Qt.Vertical) 64 slider.setMinimum(0) 65 slider.setMaximum(2) 66 slider.setInvertedAppearance(True) 67 slider.valueChanged.connect(lambda:sliderMove(slider, gearDisplay)) 68 shiftLayout.addWidget(slider) 69 sliderMove(slider, gearDisplay) 70 71 72 buttonLayout = QVBoxLayout() 73 topLevelLayout.addLayout(buttonLayout) 74 75 signalButtonGroup = QButtonGroup() 76 77 bNoSignal = QPushButton("None") 78 bNoSignal.setCheckable(True) 79 bNoSignal.setChecked(True) 80 buttonLayout.addWidget(bNoSignal) 81 signalButtonGroup.addButton(bNoSignal) 82 83 bHazards = QPushButton("Hazards") 84 bHazards.setCheckable(True) 85 buttonLayout.addWidget(bHazards) 86 signalButtonGroup.addButton(bHazards) 87 88 bLeft = QPushButton("Left") 89 bLeft.setCheckable(True) 90 buttonLayout.addWidget(bLeft) 91 signalButtonGroup.addButton(bLeft) 92 93 bRight = QPushButton("Right") 94 bRight.setCheckable(True) 95 buttonLayout.addWidget(bRight) 96 signalButtonGroup.addButton(bRight) 97 98 signalButtonGroup.buttonClicked.connect(lambda:onSignalClicked(signalButtonGroup)) 99 100 widget.show() 101 sys.exit(app.exec_()) 102 103 104def onSignalClicked(group): 105 print "signal "+group.checkedButton().text()+" is active" 106 try: 107 vhal.setProperty(c.VEHICLEPROPERTY_TURN_SIGNAL_STATE, 0, group.checkedId()) 108 except: 109 print "Ignoring error setting property 0x{:08X}".format(c.VEHICLEPROPERTY_TURN_SIGNAL_STATE) 110 111 112def sliderMove(slider, gearDisplay): 113 if slider.value() == 0: 114 gearName = 'park' 115 vhal.setProperty(c.VEHICLEPROPERTY_GEAR_SELECTION, 0, c.VEHICLEGEAR_GEAR_PARK) 116 elif slider.value() == 1: 117 gearName = 'reverse' 118 vhal.setProperty(c.VEHICLEPROPERTY_GEAR_SELECTION, 0, c.VEHICLEGEAR_GEAR_REVERSE) 119 elif slider.value() == 2: 120 gearName = 'drive' 121 vhal.setProperty(c.VEHICLEPROPERTY_GEAR_SELECTION, 0, c.VEHICLEGEAR_GEAR_DRIVE) 122 else: 123 gearName = "UNK" 124 print "slider "+slider.objectName()+" requested "+str(slider.value())+" = "+gearName 125 gearDisplay.setText(gearName) 126 127 128if __name__ == '__main__': 129 parser = argparse.ArgumentParser(description='Vehicle HAL Driver UI') 130 parser.add_argument("--serial", "-s", action='store', dest='serial', 131 default=None, required=False, help='Select which device to connect to') 132 args = parser.parse_args() 133 print "Starting VHal driver GUI" 134 vhal = Vhal(c.vhal_types_2_0, device=args.serial) 135 136 # Start a receive thread to consume any replies from the vhal 137 print "Starting receiver thread" 138 rx = Thread(target=rxThread, args=(vhal,)) 139 rx.setDaemon(True) 140 rx.start() 141 142 # Put the car in park so we start in a known state (consistent with the GUI default state) 143 vhal.setProperty(c.VEHICLEPROPERTY_GEAR_SELECTION, 0, c.VEHICLEGEAR_GEAR_PARK) 144 145 # Start the main UI -- never returns 146 window() 147