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