import wx import time import thread import usb import sys import pylab import string ID_EXIT = 1 ID_OPENCLASS = 2 ID_CONNECTUSB = 3 ID_SAVE = 4 ID_STARTQUIZ = 5 ID_LOADQUIZ = 6 ID_ENDQUESTION = 7 ID_NEXTQUESTION = 8 ID_TEXTPANEL = 9 class mainFrame(wx.Frame): def __init__(self, parent = None): wx.Frame.__init__(self, parent, -1) self.CreateStatusBar() fileMenu = wx.Menu() fileMenu.Append(ID_CONNECTUSB, "&Connect to Basestation", "Establish USB link with base station") fileMenu.Append(ID_OPENCLASS, "&Open Class", "Load class listing") fileMenu.Append(ID_SAVE, "&Save Output", "Write text to file for later parsing") fileMenu.Append(ID_EXIT, "&Exit", "Close Program") quizMenu = wx.Menu() quizMenu.Append(ID_LOADQUIZ, "&Load Quiz Questions", "Load a quiz from file") quizMenu.Append(ID_STARTQUIZ, "&Begin Quiz", "Begin current quiz") quizMenu.Append(ID_ENDQUESTION, "&End Question", "End response period for current question") quizMenu.Append(ID_NEXTQUESTION, "&Start Next Question", "Ask students next question in quiz") menuBar = wx.MenuBar() menuBar.Append(fileMenu, "&File") menuBar.Append(quizMenu, "&Quiz") self.SetMenuBar(menuBar) wx.EVT_MENU(self, ID_CONNECTUSB, self.onConnectUsb) wx.EVT_MENU(self, ID_OPENCLASS, self.onOpenClass) wx.EVT_MENU(self, ID_EXIT, self.onExit) wx.EVT_MENU(self, ID_STARTQUIZ, self.onStartQuiz) wx.EVT_MENU(self, ID_LOADQUIZ, self.onLoadQuiz) wx.EVT_MENU(self, ID_ENDQUESTION, self.onEndQuestion) wx.EVT_MENU(self, ID_NEXTQUESTION, self.onNextQuestion) wx.EVT_MENU(self, ID_SAVE, self.onSave) self.textPanel = wx.TextCtrl(self, ID_TEXTPANEL, style = wx.TE_MULTILINE | wx.TE_READONLY) wx.EVT_CHAR(self.textPanel, self.onChar) wx.EVT_CLOSE(self, self.onExit) self.SetTitle('DreamTeam Quiz') self.Show(True) def onChar(self, event = None): if event.GetKeyCode() == ord('e'): self.onEndQuestion() elif event.GetKeyCode() == ord('n'): self.onNextQuestion() elif event.GetKeyCode() == ord('l'): self.onLoadQuiz() elif event.GetKeyCode() == ord('q'): self.onStartQuiz() elif event.GetKeyCode() == ord('c'): self.onConnectUsb() elif event.GetKeyCode() == ord('s'): self.onSave() elif event.GetKeyCode() == ord('o'): self.onOpenClass() def onSave(self, event = None): saveFrame = wx.FileDialog(None, style = wx.FD_SAVE) if saveFrame.ShowModal() == wx.ID_OK: self.textPanel.SaveFile(saveFrame.GetPath()) def onOpenClass(self, event = None): global studentList, studentListLock openFrame = wx.FileDialog(None, message = "Choose a Class List", ) if openFrame.ShowModal() == wx.ID_OK: studentListLock.acquire() studentList = [] textFile = open(openFrame.GetPath()) for line in textFile: line = line[0:-1] temp = line.split(':') studentList.append(student(temp[0], temp[1], temp[2])) self.textPanel.AppendText(''.join(['Class loaded from file: ',openFrame.GetPath()])) self.textPanel.AppendText('\n') studentListLock.release() def onExit(self, event = None): global parentRunning parentRunning = False self.Destroy() def onStartQuiz(self, event = None): global quizRunning, quizRunningLock, curQuestionIndex, curQuestionIndexLock, questionList, questionListLock, questionInProgress, questionInProgressLock quizRunningLock.acquire() if not quizRunning: curQuestionIndexLock.acquire() questionListLock.acquire() questionInProgressLock.acquire() quizRunning = True questionInProgress = True curQuestionIndex = 0 self.textPanel.AppendText('Quiz has begun\n') self.textPanel.AppendText(''.join(['Question ', str(curQuestionIndex+1), ': ', questionList[curQuestionIndex]])) self.textPanel.AppendText('\n') curQuestionIndexLock.release() questionListLock.release() questionInProgressLock.release() quizRunningLock.release() def onLoadQuiz(self, event = None): global questionList, questionListLock, quizRunning, quizRunningLock, answerList, answerListLock quizRunningLock.acquire() if not quizRunning: openFrame = wx.FileDialog(None, message = "Choose a Quiz List", ) if openFrame.ShowModal() == wx.ID_OK: questionListLock.acquire() answerListLock.acquire() questionList = [] answerList = [] textFile = open(openFrame.GetPath()) for line in textFile: line = line[0:-1] formatted = line.split(':') if len(formatted[0]) > 62 or len(formatted[1]) > 30: print 'Questions and answers can only be 62 characters long' break questionList.append(''.join([formatted[0], '\0'])) answerList.append(formatted[1]) self.textPanel.AppendText(''.join(['Quiz loaded from file: ',openFrame.GetPath()])) self.textPanel.AppendText('\n') questionListLock.release() answerListLock.release() quizRunningLock.release() def onEndQuestion(self, event = None): global quizRunning, quizRunningLock, curQuestionIndex, curQuestionIndexLock, questionList, questionListLock, questionInProgress, questionInProgressLock quizRunningLock.acquire() questionInProgressLock.acquire() if quizRunning and questionInProgress: curQuestionIndexLock.acquire() questionListLock.acquire() questionInProgress = False self.textPanel.AppendText('Response period over\n') if curQuestionIndex == len(questionList)-1: curQuestionIndex = -1 quizRunning = False self.textPanel.AppendText('Quiz Over') self.textPanel.AppendText('\n') curQuestionIndexLock.release() questionListLock.release() quizRunningLock.release() questionInProgressLock.release() def onNextQuestion(self, event = None): global quizRunning, quizRunningLock, curQuestionIndex, curQuestionIndexLock, questionList, questionListLock, questionInProgress, questionInProgressLock quizRunningLock.acquire() questionInProgressLock.acquire() if quizRunning and not questionInProgress: questionListLock.acquire() curQuestionIndexLock.acquire() curQuestionIndex += 1 questionInProgress = True self.textPanel.AppendText(''.join(['Question ', str(curQuestionIndex+1), ': ', questionList[curQuestionIndex]])) self.textPanel.AppendText('\n') questionListLock.release() curQuestionIndexLock.release() quizRunningLock.release() questionInProgressLock.release() def onConnectUsb(self, event = None): global usbThread, usbThreadLock usbThreadLock.acquire() if usbThread == None: busses = usb.busses() found = False for bus in busses: for device in bus.devices: if device.idVendor == 2922: myDevice = device found = True if found == False: print 'USB device not found' usbThreadLock.release() return handle = myDevice.open() handle.setConfiguration(1) handle.claimInterface(0) usbThread = thread.start_new_thread(controlUsb, (handle,)) self.textPanel.AppendText('Basestation successfully connected') self.textPanel.AppendText('\n') usbThreadLock.release() class mainApp(wx.App): def __init__(self): wx.App.__init__(self) self.frame = mainFrame() self.SetTopWindow(self.frame) self.frame.Show(True) class student: def __init__(self, idNumber, firstName, lastName): self.idNumber = idNumber self.firstName = firstName self.lastName = lastName self.answer = None self.localId = None def behind(plot): p = plot pylab.show() sys.exit() def controlUsb(handle): global app, quizRunning, quizRunningLock, questionInProgress, questionInProgressLock, curQuestionIndex, curQuestionIndexLock, questionList, questionListLock, answerList, answerListLock, studentList, studentListLock, parentRunning, parentRunningLock studentsPresent = [] localQuestionInProgress = False localIndex = -1 while True: # Check if GUI was closed if not parentRunning: sys.exit() # Check if GUI has ended current question if localQuestionInProgress == False and questionInProgress == True: localQuestionInProgress = True ############### # HACKERY FOR GOOD GRAPH, ONE NODE choices = answerList[curQuestionIndex].split('*') N = len(choices) width = 0.5 ind = pylab.arange(N) answers = N*[0] # END HACKERY ################# elif localQuestionInProgress == True and questionInProgress == False: localQuestionInProgress = False ## ################ ## # LOST TO HACKERY ## choices = answerList[localIndex].split('*') ## N = len(choices) ## width = 0.5 ## ind = pylab.arange(N) ## answers = N*[0] ## # END LOST ## ################# for curStud in studentsPresent: ## ########### ## # LOST TO HACKERY ## if curStud.answer.isdigit(): ## index = string.atoi(curStud.answer) ## if index < N+1: ## answers[index-1] += 1 ## # END LOST ## ################## curStud.answer = None plot = pylab.bar(ind, answers, width) pylab.ylabel('Number of student responses') pylab.title((questionList[localIndex])[0:-1]) pylab.xticks(ind+width/2, tuple(choices)) #pylab.show() thread.start_new_thread(behind, (plot,)) # Check if GUI has advanced the question if localIndex != curQuestionIndex: localIndex = curQuestionIndex if localIndex != -1: #print 'Question to USB' text = ''.join([chr(1), chr(len(questionList[localIndex])), questionList[localIndex], chr(0)]) handle.interruptWrite(0x1L, text) #print len(text), text #print 'Answer to USB' temp = answerList[localIndex].split('*') text = [] for i in range(len(temp)): text.append(''.join([chr(i+49), ')', temp[i], ' '])) text.append('\0') text = ''.join(text) text = ''.join([chr(2), chr(len(text)), text]) handle.interruptWrite(0x1L, text) #print len(text), text # Check for messages from basestation buff = handle.interruptRead(0x83L, 64) # Ignore the nothing messages if len(buff) == 1: time.sleep(.5) ## else: ## ## app.frame.textPanel.AppendText('Received usb message: ') ## for i in buff: ## if i > 47 and i < 123: ## app.frame.textPanel.AppendText(chr(i)) ## app.frame.textPanel.AppendText(' ') ## else: ## app.frame.textPanel.AppendText(str(i)) ## app.frame.textPanel.AppendText(' : ') ## ## ## app.frame.textPanel.AppendText('\n') # Association messages elif buff[0] == 0 and len(buff) == 11: # convert tuple of longs for Perm ID to single string of digits tempId = [] for i in range(1,9): adder = 0 if buff[i] < 0: adder = 256 tempId.append(buff[i]+adder) for i in range(len(tempId)): tempId[i] = str(tempId[i]) while len(tempId[i]) < 3: tempId[i] = '0'+tempId[i] tempId = ''.join(tempId) # convert tuple of longs for Temp ID to single string of digits tempLocalId = [] for i in range(9,11): adder = 0 if buff[i] < 0: adder = 256 tempLocalId.append(buff[i]+adder) for i in range(len(tempLocalId)): tempLocalId[i] = str(tempLocalId[i]) while len(tempLocalId[i]) < 3: tempLocalId[i] = '0'+tempLocalId[i] tempLocalId = ''.join(tempLocalId) # check for student in current class list for curStud in studentsPresent: if curStud.idNumber == tempId: app.frame.textPanel.AppendText(''.join(['Re-joining: ', curStud.firstName, ' ', curStud.lastName, ' ', str(time.time())])) app.frame.textPanel.AppendText('\n') curStud.localId = tempLocalId break # if new member was not in class before else: for curStud in studentList: if curStud.idNumber == tempId: curStud.localId = tempLocalId app.frame.textPanel.AppendText(''.join(['Now joining: ', curStud.firstName, ' ', curStud.lastName, ' ', str(time.time())])) app.frame.textPanel.AppendText('\n') studentsPresent.append(curStud) break # Response messages elif buff[0] == 1 and len(buff) == 4 and localQuestionInProgress: tempLocalId = [] for i in range(1,3): adder = 0 if buff[i] < 0: adder = 256 tempLocalId.append(buff[i]+adder) for i in range(len(tempLocalId)): tempLocalId[i] = str(tempLocalId[i]) while len(tempLocalId[i]) < 3: tempLocalId[i] = '0'+tempLocalId[i] tempLocalId = ''.join(tempLocalId) for curStud in studentsPresent: if curStud.localId == tempLocalId: curStud.answer = chr(buff[3]) ############## # GOOD GRAPH ONE NODE HACKERY if curStud.answer.isdigit(): index = string.atoi(curStud.answer) if index < N+1: answers[index-1] += 1 # END HACKERY ################# app.frame.textPanel.AppendText(''.join([curStud.firstName, ' ', curStud.lastName, ' ', curStud.answer, ' ', str(time.time())])) app.frame.textPanel.AppendText('\n') break if __name__ == '__main__': # Create globals for inter-thread communication studentList = [] studentListLock = thread.allocate_lock() questionList = [] questionListLock = thread.allocate_lock() curQuestionIndex = -1 curQuestionIndexLock = thread.allocate_lock() quizRunning = False quizRunningLock = thread.allocate_lock() questionInProgress = False questionInProgressLock = thread.allocate_lock() answerList = [] answerListLock = thread.allocate_lock() usbThread = None usbThreadLock = thread.allocate_lock() parentRunning = True parentRunningLock = thread.allocate_lock() app = mainApp() test = 'chim' app.MainLoop()