You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
4.5 KiB
147 lines
4.5 KiB
4 months ago
|
#!/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()
|