source: trunk/brainstorms/Puzzlebox/Brainstorms/Interface.py @ 222

Last change on this file since 222 was 222, checked in by sc, 11 years ago

trunk/brainstorms/interface/puzzlebox_brainstorms_interface_design.ui:
trunk/brainstorms/Puzzlebox/Brainstorms/Interface_Design.py:

  • search buttons added for device lists

trunk/brainstorms/Puzzlebox/Brainstorms/Interface.py:

  • searchForDevices() added
  • enumerateSerialPorts() added
  • fullPortName() added
  • search button and connect support added
  • NXT support working again
File size: 29.2 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# Puzzlebox - Brainstorms - Client Interface - Qt
5#
6# Copyright Puzzlebox Productions, LLC (2010)
7#
8# This code is released under the GNU Pulic License (GPL) version 2
9# For more information please refer to http://www.gnu.org/copyleft/gpl.html
10
11__changelog__ = """\
12Last Update: 2010.11.28
13
14"""
15
16__todo__ = """
17 - server may not correctly handle multiple clients connected
18      to an embedded Brainstorms server
19 - disable autorepeating on shortcut keys
20 - update configuration.ini file with settings entered into interface
21
22"""
23
24import os, sys
25
26if (sys.platform == 'win32'):
27        import _winreg as winreg
28        import itertools
29        import re
30        import serial
31else:
32        import bluetooth
33
34try:
35        import PySide as PyQt4
36        from PySide import QtCore, QtGui, QtNetwork
37except:
38        print "Using PyQt4 module"
39        from PyQt4 import QtCore, QtGui, QtNetwork
40else:
41        print "Using PySide module"
42
43#from PyQt4 import QtCore, QtGui, QtNetwork
44#from PySide import QtCore, QtGui, QtNetwork
45
46from Interface_Design import Ui_Form as Design
47
48import simplejson as json
49
50import Configuration as configuration
51import Client as brainstorms_client
52import Puzzlebox.Brainstorms.ThinkGear.Client as thinkgear_client
53#import puzzlebox_logger
54
55#####################################################################
56# Globals
57#####################################################################
58
59DEBUG = 1
60
61THINKGEAR_POWER_THRESHOLDS = configuration.THINKGEAR_POWER_THRESHOLDS
62
63BLUETOOTH_DEVICE = configuration.NXT_BLUETOOTH_DEVICE
64
65NXT_BLUETOOTH_DEVICE = configuration.NXT_BLUETOOTH_DEVICE
66
67DEFAULT_NXT_POWER_LEVEL = configuration.DEFAULT_NXT_POWER_LEVEL
68
69THINKGEAR_SERVER_HOST = configuration.THINKGEAR_SERVER_HOST
70THINKGEAR_SERVER_PORT = configuration.THINKGEAR_SERVER_PORT
71
72DEVICE_PATH = '/dev'
73PATH_TO_HCITOOL = '/usr/bin/hcitool'
74
75#####################################################################
76# Classes
77#####################################################################
78
79class puzzlebox_brainstorms_client_interface(QtGui.QWidget, Design):
80       
81        def __init__(self, log, server=None, DEBUG=DEBUG, parent = None):
82               
83                self.log = log
84                self.DEBUG = DEBUG
85               
86                QtGui.QWidget.__init__(self, parent)
87                self.setupUi(self)
88               
89                self.configureSettings()
90                self.connectWidgets()
91               
92                self.name = "Brainstorms Interface"
93               
94                self.brainstormsServer = server
95                self.brainstormsClient = None
96               
97                self.drive_state = 'stop_motors'
98                self.current_speed = 0
99       
100       
101        ##################################################################
102       
103        def configureSettings(self):
104               
105                # Brainstorms Interface
106               
107                icon = QtGui.QIcon()
108                icon.addPixmap(QtGui.QPixmap("images/puzzlebox.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
109                self.setWindowIcon(icon)
110               
111                self.pushButtonTurnLeft.setEnabled(False)
112                self.pushButtonForward.setEnabled(False)
113                self.pushButtonTurnRight.setEnabled(False)
114                self.pushButtonTurnLeftReverse.setEnabled(False)
115                self.pushButtonReverse.setEnabled(False)
116                self.pushButtonTurnRightReverse.setEnabled(False)
117               
118                self.pushButtonConcentrationEnable.setDown(True)
119                self.pushButtonRelaxationEnable.setDown(True)
120                self.pushButtonSpeedEnable.setDown(True)
121               
122               
123                # Search for available Serial and Bluetooth devices
124                self.searchForDevices()
125               
126               
127                # LEGO Mindstorms
128                self.textLabelNXTStatus.setText("Status: Disconnected")
129               
130                # Display communication port for LEGO Mindstorms NXT device
131                #self.lineEditNXTPort.setText(NXT_BLUETOOTH_DEVICE)
132                self.comboBoxNXTPortSelect.setEnabled(True)
133               
134               
135                # RC Helicopter
136                self.textLabelHelicopterStatus.setText("Status: Disconnected")
137               
138               
139                # EEG Headset
140               
141                # Display Host for ThinkGear Connect Socket Server
142                self.lineEditThinkGearHost.setText(THINKGEAR_SERVER_HOST)
143                #self.lineEditThinkGearHost.setEnabled(False)
144               
145                # Display Port for ThinkGear Connect Socket Server
146                self.lineEditThinkGearPort.setText('%i' % THINKGEAR_SERVER_PORT)
147                #self.lineEditThinkGearPort.setEnabled(False)
148       
149       
150        ##################################################################
151       
152        def getMinimumThreshold(self, threshold):
153               
154                '''Return the minimum detection level which results
155                in a non-zero power setting'''
156               
157                minimum = 100
158               
159                threshold_keys = threshold.keys()
160                threshold_keys.sort()
161                threshold_keys.reverse()
162               
163                for key in threshold_keys:
164                       
165                        if ((threshold[key] < minimum) and \
166                                 (threshold[key] > 0)):
167                                minimum = key
168               
169               
170                return(minimum)
171       
172       
173        ##################################################################
174       
175        def configureNetworkBrainstorms(self):
176               
177                bluetooth_device = str(self.comboBoxNXTPortSelect.currentText())
178               
179                self.brainstormsClient = \
180                   brainstorms_client.puzzlebox_brainstorms_network_client( \
181                           self.log, \
182                           bluetooth_device=bluetooth_device, \
183                           parent=self)
184               
185                self.brainstormsClient.sendCommand('connect', \
186                                                   bluetooth_device=bluetooth_device)
187       
188       
189        ##################################################################
190       
191        def connectToBrainstormsServer(self):
192               
193                # Prevent attempting to connect to a device which no longer exists
194                if (sys.platform != 'win32'):
195                        device = str(self.comboBoxNXTPortSelect.currentText())
196                        if ((not device.startswith(DEVICE_PATH)) or \
197                            (not os.path.exists(device))):
198                                self.searchForDevices()
199                                return
200               
201               
202                if self.DEBUG:
203                        print "<---- [%s] Connecting to Brainstorms Server" % self.name
204               
205                self.configureNetworkBrainstorms()
206               
207                #if (self.brainstormsClient.socket.state() != QtNetwork.QAbstractSocket.ConnectedState):
208                        #QtGui.QMessageBox.information(self, \
209                                                                #self.brainstormsClient.socket.name, \
210                                           #"Failed to connect to Brainstorms socket server")
211               
212                #else:
213                self.disconnect(self.pushButtonNXTConnect, \
214                                                        QtCore.SIGNAL("clicked()"), \
215                                                        self.connectToBrainstormsServer)
216               
217                self.connect(self.pushButtonNXTConnect, \
218                                                        QtCore.SIGNAL("clicked()"), \
219                                                        self.disconnectFromBrainstormsServer)
220               
221                self.textLabelNXTStatus.setText("Status: Connected")
222                self.pushButtonNXTConnect.setText('Disconnect')
223               
224                self.comboBoxNXTPortSelect.setEnabled(False)
225                self.pushButtonNXTSearch.setEnabled(False)
226               
227                self.pushButtonTurnLeft.setEnabled(True)
228                self.pushButtonForward.setEnabled(True)
229                self.pushButtonTurnRight.setEnabled(True)
230                self.pushButtonTurnLeftReverse.setEnabled(True)
231                self.pushButtonReverse.setEnabled(True)
232                self.pushButtonTurnRightReverse.setEnabled(True)
233               
234                self.pushButtonNXTMessageOne.setEnabled(True)
235                self.pushButtonNXTMessageTwo.setEnabled(True)
236                self.pushButtonNXTMessageThree.setEnabled(True)
237                self.pushButtonNXTMessageFour.setEnabled(True)
238                self.pushButtonNXTMessageFive.setEnabled(True)
239                self.pushButtonNXTMessageSix.setEnabled(True)
240               
241                self.pushButtonConcentrationEnable.setEnabled(False)
242                self.pushButtonRelaxationEnable.setEnabled(False)
243                self.pushButtonSpeedEnable.setEnabled(False)
244               
245                self.pushButtonMessageOne.setEnabled(True)
246                self.pushButtonMessageTwo.setEnabled(True)
247                self.pushButtonMessageThree.setEnabled(True)
248                self.pushButtonMessageFour.setEnabled(True)
249                self.pushButtonMessageFive.setEnabled(True)
250                self.pushButtonMessageSix.setEnabled(True)
251       
252       
253        ##################################################################
254       
255        def disconnectFromBrainstormsServer(self):
256               
257                if self.DEBUG:
258                        print "- - [%s] Disconnecting from Brainstorms Server" % self.name
259               
260                self.stopMotors()
261               
262                # Ensure the stopMotors command has been received by the server
263                # so the NXT robot will stop before the client disconnects
264                self.brainstormsClient.socket.flush()
265               
266                self.brainstormsClient.socket.disconnectFromHost()
267               
268                self.disconnect(self.pushButtonNXTConnect, \
269                                  QtCore.SIGNAL("clicked()"), \
270                                  self.disconnectFromBrainstormsServer)
271               
272                self.connect(self.pushButtonNXTConnect, \
273                                  QtCore.SIGNAL("clicked()"), \
274                                  self.connectToBrainstormsServer)
275               
276                self.textLabelNXTStatus.setText("Status: Disconnected")
277                self.pushButtonNXTConnect.setText('Connect')
278               
279                self.comboBoxNXTPortSelect.setEnabled(True)
280                self.pushButtonNXTSearch.setEnabled(True)
281               
282                self.pushButtonTurnLeft.setEnabled(False)
283                self.pushButtonForward.setEnabled(False)
284                self.pushButtonTurnRight.setEnabled(False)
285                self.pushButtonTurnLeftReverse.setEnabled(False)
286                self.pushButtonReverse.setEnabled(False)
287                self.pushButtonTurnRightReverse.setEnabled(False)
288               
289                self.pushButtonNXTMessageOne.setEnabled(False)
290                self.pushButtonNXTMessageTwo.setEnabled(False)
291                self.pushButtonNXTMessageThree.setEnabled(False)
292                self.pushButtonNXTMessageFour.setEnabled(False)
293                self.pushButtonNXTMessageFive.setEnabled(False)
294                self.pushButtonNXTMessageSix.setEnabled(False)
295               
296                self.pushButtonConcentrationEnable.setEnabled(False)
297                self.pushButtonRelaxationEnable.setEnabled(False)
298                self.pushButtonSpeedEnable.setEnabled(False)
299               
300                self.pushButtonMessageOne.setEnabled(False)
301                self.pushButtonMessageTwo.setEnabled(False)
302                self.pushButtonMessageThree.setEnabled(False)
303                self.pushButtonMessageFour.setEnabled(False)
304                self.pushButtonMessageFive.setEnabled(False)
305                self.pushButtonMessageSix.setEnabled(False)
306               
307                self.brainstormsClient = None
308               
309                self.searchForDevices()
310       
311       
312        ##################################################################
313       
314        def connectToThinkGearHost(self):
315               
316                if self.DEBUG:
317                        print "Connecting to ThinkGear Host"
318               
319                server_host = str(self.lineEditThinkGearHost.text())
320                server_port = int(self.lineEditThinkGearPort.text())
321               
322                self.thinkgearClient = \
323                   thinkgear_client.puzzlebox_brainstorms_network_client_thinkgear( \
324                           self.log, \
325                           server_host=server_host, \
326                           server_port=server_port, \
327                           DEBUG=0, \
328                           parent=self)
329               
330                if (self.thinkgearClient.socket.state() != QtNetwork.QAbstractSocket.ConnectedState):
331                        QtGui.QMessageBox.information(self, \
332                                                                self.thinkgearClient.socket.name, \
333                                           "Failed to connect to ThinkGear socket server")
334               
335                else:
336                        self.disconnect(self.pushButtonThinkGearConnect, \
337                                                         QtCore.SIGNAL("clicked()"), \
338                                                         self.connectToThinkGearHost)
339                       
340                        self.connect(self.pushButtonThinkGearConnect, \
341                                                         QtCore.SIGNAL("clicked()"), \
342                                                         self.disconnectFromThinkGearHost)
343                       
344                        self.pushButtonThinkGearConnect.setText('Disconnect')
345                       
346                        self.lineEditThinkGearHost.setEnabled(False)
347                        self.lineEditThinkGearPort.setEnabled(False)
348       
349       
350        ##################################################################
351       
352        def disconnectFromThinkGearHost(self):
353               
354                if self.DEBUG:
355                        print "Disconnecting from ThinkGear Host"
356               
357                self.thinkgearClient.disconnectFromHost()
358               
359                self.disconnect(self.pushButtonThinkGearConnect, \
360                                  QtCore.SIGNAL("clicked()"), \
361                                  self.disconnectFromThinkGearHost)
362               
363                self.connect(self.pushButtonThinkGearConnect, \
364                                  QtCore.SIGNAL("clicked()"), \
365                                  self.connectToThinkGearHost)
366               
367                self.pushButtonForward.emit(QtCore.SIGNAL("released()"))
368               
369                self.pushButtonThinkGearConnect.setText('Connect')
370               
371                self.lineEditThinkGearHost.setEnabled(True)
372                self.lineEditThinkGearPort.setEnabled(True)
373               
374                self.progressBarConcentration.setValue(0)
375                self.progressBarRelaxation.setValue(0)
376                self.progressBarSpeed.setValue(0)
377       
378       
379        ##################################################################
380       
381        def updateConcentrationButton(self):
382               
383                if self.pushButtonConcentrationEnable.isChecked():
384                       
385                        self.pushButtonConcentrationEnable.setText('Enabled')
386               
387                else:
388                       
389                        self.pushButtonConcentrationEnable.setText('Disabled')
390                        self.progressBarConcentration.setValue(0)
391               
392               
393                self.updateSpeed()
394       
395       
396        ##################################################################
397       
398        def updateRelaxationButton(self):
399               
400                if self.pushButtonRelaxationEnable.isChecked():
401               
402                        self.pushButtonRelaxationEnable.setText('Enabled')
403               
404                else:
405                       
406                        self.pushButtonRelaxationEnable.setText('Disabled')
407                        self.progressBarRelaxation.setValue(0)
408               
409               
410                self.updateSpeed()
411       
412       
413        ##################################################################
414       
415        def updateSpeedButton(self):
416               
417                if self.pushButtonSpeedEnable.isChecked():
418               
419                        self.pushButtonSpeedEnable.setText('Enabled')
420                        self.updateSpeed()
421               
422                else:
423                       
424                        self.pushButtonSpeedEnable.setText('Disabled')
425                        self.progressBarSpeed.setValue(0)
426                        self.stopMotors()
427       
428       
429        ##################################################################
430       
431        def connectWidgets(self):
432               
433                # LEGO Mindstorms Buttons
434                self.connect(self.pushButtonTurnLeft, QtCore.SIGNAL("pressed()"), \
435                             self.turnLeft)
436                self.connect(self.pushButtonTurnLeft, QtCore.SIGNAL("released()"), \
437                             self.stopMotors)
438               
439                self.connect(self.pushButtonForward, QtCore.SIGNAL("pressed()"), \
440                             self.driveForward)
441                self.connect(self.pushButtonForward, QtCore.SIGNAL("released()"), \
442                             self.stopMotors)
443               
444                self.connect(self.pushButtonTurnRight, QtCore.SIGNAL("pressed()"), \
445                             self.turnRight)
446                self.connect(self.pushButtonTurnRight, QtCore.SIGNAL("released()"), \
447                             self.stopMotors)
448               
449                self.connect(self.pushButtonTurnLeftReverse, QtCore.SIGNAL("pressed()"), \
450                             self.turnLeftInReverse)
451                self.connect(self.pushButtonTurnLeftReverse, QtCore.SIGNAL("released()"), \
452                             self.stopMotors)
453               
454                self.connect(self.pushButtonReverse, QtCore.SIGNAL("pressed()"), \
455                             self.driveReverse)
456                self.connect(self.pushButtonReverse, QtCore.SIGNAL("released()"), \
457                             self.stopMotors)
458               
459                self.connect(self.pushButtonTurnRightReverse, QtCore.SIGNAL("pressed()"), \
460                             self.turnRightInReverse)
461                self.connect(self.pushButtonTurnRightReverse, QtCore.SIGNAL("released()"), \
462                             self.stopMotors)
463               
464               
465                self.connect(self.pushButtonNXTSearch, \
466                                  QtCore.SIGNAL("clicked()"), \
467                                  self.searchForDevices)
468               
469                self.connect(self.pushButtonNXTConnect, \
470                                  QtCore.SIGNAL("clicked()"), \
471                                  self.connectToBrainstormsServer)
472               
473               
474                self.connect(self.pushButtonConcentrationEnable, \
475                                  QtCore.SIGNAL("clicked()"), \
476                                  self.updateConcentrationButton)
477               
478                self.connect(self.pushButtonRelaxationEnable, \
479                                  QtCore.SIGNAL("clicked()"), \
480                                  self.updateRelaxationButton)
481               
482                self.connect(self.pushButtonSpeedEnable, \
483                                  QtCore.SIGNAL("clicked()"), \
484                                  self.updateSpeedButton)
485               
486               
487                self.connect(self.pushButtonNXTMessageOne, QtCore.SIGNAL("pressed()"), \
488                             self.sendMessageOne)
489               
490                self.connect(self.pushButtonNXTMessageTwo, QtCore.SIGNAL("pressed()"), \
491                             self.sendMessageTwo)
492               
493                self.connect(self.pushButtonNXTMessageThree, QtCore.SIGNAL("pressed()"), \
494                             self.sendMessageThree)
495               
496                self.connect(self.pushButtonNXTMessageFour, QtCore.SIGNAL("pressed()"), \
497                             self.sendMessageFour)
498               
499                self.connect(self.pushButtonNXTMessageFive, QtCore.SIGNAL("pressed()"), \
500                             self.sendMessageFive)
501               
502                self.connect(self.pushButtonNXTMessageSix, QtCore.SIGNAL("pressed()"), \
503                             self.sendMessageSix)
504               
505               
506               
507                # RC Helicopter Buttons
508                self.connect(self.pushButtonHelicopterSearch, \
509                                  QtCore.SIGNAL("clicked()"), \
510                                  self.searchForDevices)
511               
512                #self.connect(self.pushButtonHelicopterConnect, \
513                                  #QtCore.SIGNAL("clicked()"), \
514                                  #self.connectToHelicopter)
515               
516               
517               
518                # Control Panel Buttons
519                self.connect(self.pushButtonMessageOne, QtCore.SIGNAL("pressed()"), \
520                             self.sendMessageOne)
521               
522                self.connect(self.pushButtonMessageTwo, QtCore.SIGNAL("pressed()"), \
523                             self.sendMessageTwo)
524               
525                self.connect(self.pushButtonMessageThree, QtCore.SIGNAL("pressed()"), \
526                             self.sendMessageThree)
527               
528                self.connect(self.pushButtonMessageFour, QtCore.SIGNAL("pressed()"), \
529                             self.sendMessageFour)
530               
531                self.connect(self.pushButtonMessageFive, QtCore.SIGNAL("pressed()"), \
532                             self.sendMessageFive)
533               
534                self.connect(self.pushButtonMessageSix, QtCore.SIGNAL("pressed()"), \
535                             self.sendMessageSix)
536               
537               
538                self.connect(self.pushButtonThinkGearConnect, \
539                                  QtCore.SIGNAL("clicked()"), \
540                                  self.connectToThinkGearHost)
541               
542               
543                #shortcut = QtGui.QShortcut(self)
544                #shortcut.setKey(tr("Down"))
545                #self.connect(shortcut, QtCore.SIGNAL("pressed()"), self.driveReverse)
546               
547               
548                action = QtGui.QAction(self)
549                action.setShortcut(QtGui.QKeySequence("W"))
550                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonForward, QtCore.SLOT("animateClick()"))
551                self.addAction(action)
552               
553                action = QtGui.QAction(self)
554                action.setShortcut(QtGui.QKeySequence("Up"))
555                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonForward, QtCore.SLOT("animateClick()"))
556                self.addAction(action)
557               
558               
559                action = QtGui.QAction(self)
560                action.setShortcut(QtGui.QKeySequence("Left"))
561                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonTurnLeft, QtCore.SLOT("animateClick()"))
562                self.addAction(action)
563               
564                action = QtGui.QAction(self)
565                action.setShortcut(QtGui.QKeySequence("A"))
566                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonTurnLeft, QtCore.SLOT("animateClick()"))
567                self.addAction(action)
568               
569               
570                action = QtGui.QAction(self)
571                action.setShortcut(QtGui.QKeySequence("S"))
572                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonReverse, QtCore.SLOT("animateClick()"))
573                self.addAction(action)
574               
575                action = QtGui.QAction(self)
576                action.setShortcut(QtGui.QKeySequence("Down"))
577                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonReverse, QtCore.SLOT("animateClick()"))
578                self.addAction(action)
579               
580               
581                action = QtGui.QAction(self)
582                action.setShortcut(QtGui.QKeySequence("D"))
583                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonTurnRight, QtCore.SLOT("animateClick()"))
584                self.addAction(action)
585               
586                action = QtGui.QAction(self)
587                action.setShortcut(QtGui.QKeySequence("Right"))
588                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonTurnRight, QtCore.SLOT("animateClick()"))
589                self.addAction(action)
590               
591               
592                action = QtGui.QAction(self)
593                action.setShortcut(QtGui.QKeySequence("Z"))
594                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonTurnLeftReverse, QtCore.SLOT("animateClick()"))
595                self.addAction(action)
596               
597               
598                action = QtGui.QAction(self)
599                action.setShortcut(QtGui.QKeySequence("C"))
600                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonTurnRightReverse, QtCore.SLOT("animateClick()"))
601                self.addAction(action)
602               
603               
604                # Control Panel Buttons
605               
606                action = QtGui.QAction(self)
607                action.setShortcut(QtGui.QKeySequence("1"))
608                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonNXTMessageOne, QtCore.SLOT("animateClick()"))
609                self.addAction(action)
610               
611                action = QtGui.QAction(self)
612                action.setShortcut(QtGui.QKeySequence("2"))
613                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonNXTMessageTwo, QtCore.SLOT("animateClick()"))
614                self.addAction(action)
615               
616                action = QtGui.QAction(self)
617                action.setShortcut(QtGui.QKeySequence("3"))
618                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonNXTMessageThree, QtCore.SLOT("animateClick()"))
619                self.addAction(action)
620               
621                action = QtGui.QAction(self)
622                action.setShortcut(QtGui.QKeySequence("4"))
623                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonNXTMessageFour, QtCore.SLOT("animateClick()"))
624                self.addAction(action)
625               
626                action = QtGui.QAction(self)
627                action.setShortcut(QtGui.QKeySequence("5"))
628                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonNXTMessageFive, QtCore.SLOT("animateClick()"))
629                self.addAction(action)
630               
631                action = QtGui.QAction(self)
632                action.setShortcut(QtGui.QKeySequence("6"))
633                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonNXTMessageSix, QtCore.SLOT("animateClick()"))
634                self.addAction(action)
635               
636               
637                #self.pushButtonForward.setAutoRepeat(False)
638                #self.pushButtonForward.setAutoRepeatDelay(0)
639                #self.pushButtonForward.setAutoRepeatInterval(0)
640       
641       
642        ##################################################################
643       
644        def searchForDevices(self):
645               
646                nxt_devices = []
647                rc_helicopter_devices = []
648               
649                #if (sys.platform != 'win32'):
650                if False: # temporarily disabled
651                       
652                        # Bluetooth module doesn't compile properly under Windows
653                       
654                        bluetooth_devices = []
655                       
656                        try:
657                                bluetooth_devices = bluetooth.discover_devices( \
658                                                       duration=5, \
659                                                       flush_cache=True, \
660                                                       lookup_names=False)
661                        except:
662                                #command = '%s con' % PATH_TO_HCITOOL
663                                command = '%s scan' % PATH_TO_HCITOOL
664                               
665                                output = os.popen(command, 'r')
666                               
667                                for line in output.readlines():
668                                        print line
669                                        try:
670                                                address = line.split(' ')[2]
671                                        except:
672                                                pass
673                                        else:
674                                                bluetooth_devices.append(address)
675                       
676                        for address in bluetooth_devices:
677                                device_name = bluetooth.lookup_name(address)
678                                if ((device_name == 'NXT') and \
679                                    (address not in nxt_devices)):
680                                        nxt_devices.append(address)
681                       
682                       
683                        if self.DEBUG:
684                                print "Bluetooth NXT devices found:",
685                                print nxt_devices
686               
687               
688                # List all serial devices
689                serial_devices = self.enumerateSerialPorts()
690               
691                for serial_device in serial_devices:
692                        #serial_device = self.fullPortName(serial_device)
693                        nxt_devices.append(serial_device)
694                        rc_helicopter_devices.append(serial_device)
695               
696               
697                # Configure combo boxes
698                if nxt_devices == []:
699                        nxt_devices.append('N/A')
700               
701                if rc_helicopter_devices == []:
702                        rc_helicopter_devices.append('N/A')
703               
704               
705                # Don't reset combo boxes if already connected
706                if self.pushButtonNXTConnect.text != 'Disconnect':
707                       
708                        self.comboBoxNXTPortSelect.clear()
709                       
710                        #nxt_devices.reverse()
711                        for nxt_device in nxt_devices:
712                                self.comboBoxNXTPortSelect.addItem(nxt_device)
713               
714               
715                if self.pushButtonHelicopterConnect.text != 'Disconnect':
716                       
717                        self.comboBoxHelicopterPortSelect.clear()
718                       
719                        #rc_helicopter_devices.reverse()
720                        for rc_helicopter in rc_helicopter_devices:
721                                self.comboBoxHelicopterPortSelect.addItem(rc_helicopter)
722       
723       
724        ##################################################################
725       
726        def enumerateSerialPorts(self):
727               
728                """ Uses the Win32 registry to return an
729                iterator of serial (COM) ports
730                existing on this computer.
731               
732                from http://eli.thegreenplace.net/2009/07/31/listing-all-serial-ports-on-windows-with-python/
733                """
734               
735                serial_ports = []
736               
737                if (sys.platform == 'win32'):
738                       
739                        path = 'HARDWARE\\DEVICEMAP\\SERIALCOMM'
740                        try:
741                                key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, path)
742                        except WindowsError:
743                                #raise IterationError
744                                #return
745                                pass
746                       
747                        for i in itertools.count():
748                                try:
749                                        val = winreg.EnumValue(key, i)
750                                        #yield str(val[1])
751                                        serial_ports.append( str(val[1]) )
752                                except EnvironmentError:
753                                        break
754               
755               
756                else:
757                       
758                        if os.path.exists(DEVICE_PATH):
759                                device_list = os.listdir(DEVICE_PATH)
760                               
761                                device_list.sort()
762                       
763                                for device in device_list:
764                                        if device.startswith('ttyUSB'):
765                                                serial_ports.append( DEVICE_PATH + '/' + device )
766                                        if device.startswith('rfcomm'):
767                                                serial_ports.append( DEVICE_PATH + '/' + device )
768                                        if device.startswith('ttyACM'):
769                                                serial_ports.append( DEVICE_PATH + '/' + device )
770                                        if device.startswith('ttyS'):
771                                                serial_ports.append( DEVICE_PATH + '/' + device )
772               
773               
774                return(serial_ports)
775       
776       
777        ##################################################################
778       
779        def fullPortName(self, portname):
780               
781                """ Given a port-name (of the form COM7,
782                COM12, CNCA0, etc.) returns a full
783                name suitable for opening with the
784                Serial class.
785                """
786               
787                m = re.match('^COM(\d+)$', portname)
788                if m and int(m.group(1)) < 10:
789                        return portname
790               
791                return '\\\\.\\' + portname
792       
793       
794        ##################################################################
795       
796        def turnLeft(self):
797                self.brainstormsClient.sendCommand('turn_left')
798                self.drive_state = 'turn_left'
799       
800        def driveForward(self):
801                #if self.DEBUG:
802                        #print "driveForward"
803                self.pushButtonForward.setDown(True)
804                if (self.drive_state != 'drive_forward'):
805                        self.updateSpeed(new_speed=DEFAULT_NXT_POWER_LEVEL)
806                self.brainstormsClient.sendCommand('drive_forward', power=self.current_speed)
807                self.drive_state = 'drive_forward'
808       
809        def turnRight(self):
810                self.brainstormsClient.sendCommand('turn_right')
811                self.drive_state = 'turn_right'
812       
813        def turnLeftInReverse(self):
814                self.brainstormsClient.sendCommand('turn_left_in_reverse')
815                self.drive_state = 'turn_left_in_reverse'
816       
817        def driveReverse(self):
818                self.brainstormsClient.sendCommand('drive_reverse')
819                self.drive_state = 'drive_reverse'
820       
821        def turnRightInReverse(self):
822                self.brainstormsClient.sendCommand('turn_right_in_reverse')
823                self.drive_state = 'turn_right_in_reverse'
824       
825        def stopMotors(self):
826                self.pushButtonForward.setDown(False)
827                if (self.current_speed != 0):
828                        self.updateSpeed(new_speed=0)
829                if self.brainstormsClient != None:
830                        self.brainstormsClient.sendCommand('stop_motors')
831                self.drive_state = 'stop_motors'
832       
833        def sendMessageOne(self):
834                message = str(self.lineEditMessageOne.text())
835                self.brainstormsClient.sendCommand('send_message_1')
836       
837        def sendMessageTwo(self):
838                message = str(self.lineEditMessageTwo.text())
839                self.brainstormsClient.sendCommand('send_message_2')
840       
841        def sendMessageThree(self):
842                message = str(self.lineEditMessageThree.text())
843                self.brainstormsClient.sendCommand('send_message_3')
844       
845        def sendMessageFour(self):
846                message = str(self.lineEditMessageFour.text())
847                self.brainstormsClient.sendCommand('send_message_4')
848       
849        def sendMessageFive(self):
850                message = str(self.lineEditMessageFive.text())
851                self.brainstormsClient.sendCommand('send_message_5')
852       
853        def sendMessageSix(self):
854                message = str(self.lineEditMessageSix.text())
855                self.brainstormsClient.sendCommand('send_message_6')
856       
857       
858        ##################################################################
859       
860        def updateSpeed(self, new_speed=None):
861               
862                if new_speed == None:
863               
864                        concentration=self.progressBarConcentration.value()
865                        relaxation=self.progressBarRelaxation.value()
866                       
867                        new_speed = self.calculateSpeed(concentration, relaxation)
868               
869               
870                # Update GUI
871                if self.pushButtonSpeedEnable.isChecked():
872                        self.progressBarSpeed.setValue(new_speed)
873               
874               
875                # If there is a change between the new and current speeds
876                # and either the robot is currently driving forward
877                # or the "speed control" button is enabled,
878                # then send the updated speed to the robot
879                if ((self.current_speed != new_speed) and \
880                         ((self.drive_state == 'drive_forward') or \
881                          (self.pushButtonSpeedEnable.isChecked()))):
882                       
883                        if (new_speed == 0):
884                                self.current_speed = new_speed
885                                self.stopMotors()
886                        else:
887                                if ((self.brainstormsClient != None) and \
888                                    (self.pushButtonSpeedEnable.isChecked())):
889                                        self.pushButtonForward.setDown(True)
890                                        self.brainstormsClient.sendCommand('drive_forward', power=new_speed)
891               
892               
893                self.current_speed = new_speed
894       
895       
896        ##################################################################
897       
898        def calculateSpeed(self, concentration, relaxation):
899               
900                speed = 0
901               
902                thresholds = THINKGEAR_POWER_THRESHOLDS
903               
904                match = int(concentration)
905               
906                while ((match not in thresholds['concentration'].keys()) and \
907                            (match >= 0)):
908                        match -= 1
909               
910               
911                if match in thresholds['concentration'].keys():
912                        speed = thresholds['concentration'][match]
913               
914               
915                match = int(relaxation)
916               
917                while ((match not in thresholds['relaxation'].keys()) and \
918                            (match >= 0)):
919                        match -= 1
920               
921                if match in thresholds['relaxation'].keys():
922                        speed = speed + thresholds['relaxation'][match]
923               
924               
925                # LEGO Mindstorms power settings cannot exceed 100
926                # and don't drive well with levels less than 50
927                if (speed > 100):
928                        speed = 100
929                elif (speed < 50):
930                        speed = 0
931               
932               
933                return(speed)
934       
935       
936        ##################################################################
937       
938        def processPacketThinkGear(self, packet):
939               
940                if ('eSense' in packet.keys()):
941                       
942                        if ('attention' in packet['eSense'].keys()):
943                                if self.pushButtonConcentrationEnable.isChecked():
944                                        self.progressBarConcentration.setValue(packet['eSense']['attention'])
945                       
946                        if ('meditation' in packet['eSense'].keys()):
947                                if self.pushButtonRelaxationEnable.isChecked():
948                                        self.progressBarRelaxation.setValue(packet['eSense']['meditation'])
949               
950               
951                self.updateSpeed()
952       
953       
954        ##################################################################
955       
956        def closeEvent(self, event):
957               
958                quit_message = "Are you sure you want to exit the program?"
959               
960                reply = QtGui.QMessageBox.question( \
961                           self, \
962                          'Message', \
963                           quit_message, \
964                           QtGui.QMessageBox.Yes, \
965                           QtGui.QMessageBox.No)
966               
967                if reply == QtGui.QMessageBox.Yes:
968                       
969                        if self.brainstormsClient != None:
970                                self.stopMotors()
971                                self.brainstormsClient.socket.flush()
972                               
973                                if self.brainstormsServer != None:
974                                       
975                                        if self.brainstormsServer.rc == None:
976                                               
977                                                bluetooth_device = str(self.comboBoxNXTPortSelect.currentText())
978                                                self.brainstormsServer.executeCommand( \
979                                                        'stop_motors', \
980                                                        bluetooth_device=bluetooth_device)
981                                               
982                                        else:
983                                                self.brainstormsServer.rc.run('stop_motors')
984                       
985                       
986                        event.accept()
987               
988                else:
989                        event.ignore()
990
991
992#####################################################################
993# Functions
994#####################################################################
995
996#####################################################################
997# Main
998#####################################################################
999
1000if __name__ == '__main__':
1001       
1002        #log = puzzlebox_logger.puzzlebox_logger(logfile='client_interface')
1003        log = None
1004       
1005        app = QtGui.QApplication(sys.argv)
1006       
1007        window = puzzlebox_brainstorms_client_interface(log, DEBUG)
1008        window.show()
1009       
1010        sys.exit(app.exec_())
1011
Note: See TracBrowser for help on using the repository browser.