| #!/usr/bin/env python |
| # |
| # Copyright (C) 2017 The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| |
| # A simple GUI to remotely actuate the Vehicle HAL via the eumalator |
| |
| import argparse |
| import sys |
| from threading import Thread |
| from PyQt4.QtCore import * |
| from PyQt4.QtGui import * |
| |
| import VehicleHalProto_pb2 |
| from vhal_emulator import Vhal |
| import vhal_consts_2_0 as c |
| |
| |
| # Define a simple thread that receives messages from a vhal object (v) and prints them |
| def rxThread(v): |
| while(1): |
| msg = v.rxMsg() |
| if (msg.msg_type == VehicleHalProto_pb2.SET_PROPERTY_RESP): |
| if msg.status == 0: |
| print "Success ("+str(msg.status)+")" |
| else: |
| print "Error ("+str(msg.status)+")" |
| else: |
| print msg; |
| |
| |
| # Main window setup |
| def window(): |
| app = QApplication(sys.argv) |
| widget = QWidget() |
| widget.setWindowTitle("VHal Driver") |
| widget.setGeometry(100,100,200,50) |
| topLevelLayout = QHBoxLayout() |
| widget.setLayout(topLevelLayout) |
| |
| shiftLayout = QVBoxLayout() |
| topLevelLayout.addLayout(shiftLayout) |
| |
| gearTitle = QLabel(widget) |
| gearTitle.setText("Gear Shift") |
| shiftLayout.addWidget(gearTitle); |
| |
| gearDisplay = QLabel(widget) |
| shiftLayout.addWidget(gearDisplay); |
| |
| slider = QSlider(Qt.Vertical) |
| slider.setMinimum(0) |
| slider.setMaximum(2) |
| slider.setInvertedAppearance(True) |
| slider.valueChanged.connect(lambda:sliderMove(slider, gearDisplay)) |
| shiftLayout.addWidget(slider) |
| sliderMove(slider, gearDisplay) |
| |
| |
| buttonLayout = QVBoxLayout() |
| topLevelLayout.addLayout(buttonLayout) |
| |
| signalButtonGroup = QButtonGroup() |
| |
| bNoSignal = QPushButton("None") |
| bNoSignal.setCheckable(True) |
| bNoSignal.setChecked(True) |
| buttonLayout.addWidget(bNoSignal) |
| signalButtonGroup.addButton(bNoSignal) |
| |
| bHazards = QPushButton("Hazards") |
| bHazards.setCheckable(True) |
| buttonLayout.addWidget(bHazards) |
| signalButtonGroup.addButton(bHazards) |
| |
| bLeft = QPushButton("Left") |
| bLeft.setCheckable(True) |
| buttonLayout.addWidget(bLeft) |
| signalButtonGroup.addButton(bLeft) |
| |
| bRight = QPushButton("Right") |
| bRight.setCheckable(True) |
| buttonLayout.addWidget(bRight) |
| signalButtonGroup.addButton(bRight) |
| |
| signalButtonGroup.buttonClicked.connect(lambda:onSignalClicked(signalButtonGroup)) |
| |
| widget.show() |
| sys.exit(app.exec_()) |
| |
| |
| def onSignalClicked(group): |
| print "signal "+group.checkedButton().text()+" is active" |
| try: |
| vhal.setProperty(c.VEHICLEPROPERTY_TURN_SIGNAL_STATE, 0, group.checkedId()) |
| except: |
| print "Ignoring error setting property 0x{:08X}".format(c.VEHICLEPROPERTY_TURN_SIGNAL_STATE) |
| |
| |
| def sliderMove(slider, gearDisplay): |
| if slider.value() == 0: |
| gearName = 'park' |
| vhal.setProperty(c.VEHICLEPROPERTY_GEAR_SELECTION, 0, c.VEHICLEGEAR_GEAR_PARK) |
| elif slider.value() == 1: |
| gearName = 'reverse' |
| vhal.setProperty(c.VEHICLEPROPERTY_GEAR_SELECTION, 0, c.VEHICLEGEAR_GEAR_REVERSE) |
| elif slider.value() == 2: |
| gearName = 'drive' |
| vhal.setProperty(c.VEHICLEPROPERTY_GEAR_SELECTION, 0, c.VEHICLEGEAR_GEAR_DRIVE) |
| else: |
| gearName = "UNK" |
| print "slider "+slider.objectName()+" requested "+str(slider.value())+" = "+gearName |
| gearDisplay.setText(gearName) |
| |
| |
| if __name__ == '__main__': |
| parser = argparse.ArgumentParser(description='Vehicle HAL Driver UI') |
| parser.add_argument("--serial", "-s", action='store', dest='serial', |
| default=None, required=False, help='Select which device to connect to') |
| args = parser.parse_args() |
| print "Starting VHal driver GUI" |
| vhal = Vhal(c.vhal_types_2_0, device=args.serial) |
| |
| # Start a receive thread to consume any replies from the vhal |
| print "Starting receiver thread" |
| rx = Thread(target=rxThread, args=(vhal,)) |
| rx.setDaemon(True) |
| rx.start() |
| |
| # Put the car in park so we start in a known state (consistent with the GUI default state) |
| vhal.setProperty(c.VEHICLEPROPERTY_GEAR_SELECTION, 0, c.VEHICLEGEAR_GEAR_PARK) |
| |
| # Start the main UI -- never returns |
| window() |