commit 6a8ea069c751a4c9dbfe6fc53ae57496474cd51a Author: weberni69795 Date: Fri Nov 19 13:49:25 2021 +0000 Raspery-code diff --git a/UIController.py b/UIController.py new file mode 100644 index 0000000..f76f2e4 --- /dev/null +++ b/UIController.py @@ -0,0 +1,327 @@ +'''-------------------------------------------------------------------------------------------------- +Im Controller wird in der Init eine View erstellt und gestartet. Zudem wird der Acquisitionserver +gestartet, die shared Librarz geladen, die Konstanten Initialtisiert. +Mittels der Funktion Action Performed wird die jeweilige Reaktion auf die Benutyeraktion ausgeloest. +Hierfuer stehen die verschiedenen eigenen Funktionen die die Reaktion in der richtigen reihenfolge +an ein neu instanizieertes Modell weitergibt. +Zudem stehen einige Funktionen zur Informationsuebergabe an die View oder das Modell zur Verfuegung +''' + + +from UIModellVisuell import * +from UIModellTaktil import * +from UIModell import * +import UIViewTKinter as viewTkinter +from shutil import copyfile +import ctypes +import os + + + +class Controller(): + + def __init__(self): + '''-------------------------------------------------------------------------------------------------- + In der Init wird die shared Library geladen, die View erstellt und geoeffnet und die verschiedenen + Konstanten gesetzt + ''' + + self.getSharedLibrary() + + self.view = viewTkinter.View(self, self.dll.getDefaultPath()) + self.modi = "visuellesBCI" + self.pathOVFile = self.dll.getPathOVFile() + self.pathSpatialCfg = self.dll.getSpatialCFGFile() + self.pathClassifierCfg = self.dll.getClassifierCFGFile() + self.infotext = "" + + self.commands = { + "copySpelling": self.commandoCopySpelling, + "stop": self.commandStop, + "freeSpelling": self.commandFreeSpelling, + "test": self.test, + "wechsel": self.wechsel, + "speicherort": self.setDataset + } + + self.nexts = { + "filterXdawn" : self.filterXdawn, + "filterClassic": self.filterClassic, + "save": self.speichern + } + + self.pagesTaktil = { + "stop": "StartPage", + "copySpelling": "WorkingPageTaktil", + "freeSpelling": "WorkingPageTaktil", + "test": "WorkingPageTaktil" + } + self.pagesVisuell = { + "stop": "StartPage", + "copySpelling": "WorkingPageVisuell", + "freeSpelling": "WorkingPageVisuell", + "test": "WorkingPageVisuell" + } + self.acquisitionServer = Modell(self, self.dll) + self.acquisitionServer.start() + + self.model = None + self.view.mainloop() + + def getSharedLibrary(self): + '''-------------------------------------------------------------------------------------------------- + Laedt die shared Library (diese muss sich im gleichen Ordner wie die ausfuehrunde Datei befinden) + und setzt die Eingabe und Rueckgabewerte. + ''' + + path = os.path.abspath(".") + path = path + "/dll.so" + self.dll = ctypes.CDLL(path) + + self.dll.getCommandFreespellingTaktil.argtypes = [] + self.dll.getCommandFreespellingTaktil.restype = ctypes.c_char_p + + self.dll.getCommandFreespellingVisuell.argtypes = [] + self.dll.getCommandFreespellingVisuell.restype = ctypes.c_char_p + + self.dll.getCommandCopyspellingTaktil.argtypes = [] + self.dll.getCommandCopyspellingTaktil.restype = ctypes.c_char_p + + self.dll.getCommandCopyspellingVisuell.argtypes = [] + self.dll.getCommandCopyspellingVisuell.restype = ctypes.c_char_p + + self.dll.getCommandXDawn.argtypes = [] + self.dll.getCommandXDawn.restype = ctypes.c_char_p + + self.dll.getCommandClassifier.argtypes = [] + self.dll.getCommandClassifier.restype = ctypes.c_char_p + + self.dll.getDefaultPath.argtypes = [] + self.dll.getDefaultPath.restype = ctypes.c_char_p + + self.dll.getPathOVFile.argtypes = [] + self.dll.getPathOVFile.restype = ctypes.c_char_p + + self.dll.getSpatialCFGFile.argtypes = [] + self.dll.getSpatialCFGFile.restype = ctypes.c_char_p + + self.dll.getClassifierCFGFile.argtypes = [] + self.dll.getClassifierCFGFile.restype = ctypes.c_char_p + + self.dll.getCommandStartAquisitionServer.argtypes = [] + self.dll.getCommandStartAquisitionServer.restype = ctypes.c_char_p + + def actionPerformed(self, action): + '''-------------------------------------------------------------------------------------------------- + Wird aufgerufen wenn ein Button in der Init gedrueckt wird zuerst wird kontrolliert ob die Seite + gewechselt werden muss, dann nach dem Buttonnamen die Funktion zugeordnert. Der Funktion zum + Buttomnamen wird in der Init festgelegt + ''' + + self.changePage(action) + func = self.commands.get(action) + if(func is not None): + func() + else: + print("Kommado existiert nicht") + + + def changePage(self,action): + '''-------------------------------------------------------------------------------------------------- + Change Page ruft je nach Aktion und Modi die jeweilige Seite auf + ''' + + if(self.modi == "taktilesBCI"): + page = self.pagesTaktil.get(action) + elif(self.modi == "visuellesBCI"): + page = self.pagesVisuell.get(action) + if(page is not None): + self.view.changeFrame(page) + + def wechsel(self): + '''-------------------------------------------------------------------------------------------------- + Wechsel aendert den Modi. Dafuer wird zuerst der aktuelle Modi ueberprueft und dann auf den anderen + Modi gesetzt. + ''' + + self.resetInfo() + self.addInfoText("") + if(self.modi == "taktilesBCI"): + self.view.setChangeBtnText("Wechsel zu taktilen BCI") + self.view.setTitleText("visuelles BCI") + self.modi = "visuellesBCI" + elif(self.modi == "visuellesBCI"): + self.setTitle("taktiles BCI") + self.view.setChangeBtnText("Wechsel zu visuellen BCI") + self.modi = "taktilesBCI" + + def speichern(self): + '''-------------------------------------------------------------------------------------------------- + wird nach dem Classifier Training aufgerufen und speichert die erstellte .ov Datei und die + spatial.cfg, classifier.cgf-Dateine unter dem ausgewaehlten Ordnername. + (Ordnername wird zu Beginn des CopySpellings festgelegt) + ''' + print("saveFile") + print(self.file) + os.mkdir(self.file) + copyfile(self.pathOVFile, (self.file + "/p300-xdawn-train.ov")) + copyfile(self.pathClassifierCfg, (self.file + "/p300-classifier.cfg")) + copyfile(self.pathSpatialCfg, (self.file + "/p300-spatial-filter.cfg")) + + #copyfile(self.pathOVFile, self.file) + + def setDataset(self): + '''-------------------------------------------------------------------------------------------------- + Legt fest welches Datenset fuer das Freestelling genutzt wird + ''' + + file = self.view.openfiledialog() + print(file) + if not file: + print("nichts ausgewaehlt") + else: + if os.path.exists((file + "/p300-classifier.cfg")): + print("classifier kopiert") + copyfile((file + "/p300-classifier.cfg"), self.pathClassifierCfg) + if os.path.exists((file + "/p300-spatial-filter.cfg")): + print("spatialfilter kopiert") + copyfile((file + "/p300-spatial-filter.cfg"), self.pathSpatialCfg) + if os.path.exists((file + "/p300-xdawn-train.ov")): + print(".ov kopiert") + copyfile((file + "/p300-xdawn-train.ov"), self.pathOVFile) + + + + def test(self): + '''-------------------------------------------------------------------------------------------------- + Funktion zum testen von xDawn und ClassifierTraining + ''' + self.file = self.view.savefiledialog() + if(self.modi == "taktilesBCI"): + self.model = ModellTaktil(self, dll=self.dll) + elif(self.modi == "visuellesBCI"): + self.model = ModellVisuell(self, dll=self.dll) + self.model.setFunktion(self.model.trainXDawn) + self.model.start() + + def commandoCopySpelling(self): + self.view.savefiledialog() + + + def copyspelling(self, path): + '''-------------------------------------------------------------------------------------------------- + Speichert den gewuenschte Pfad und erstellt anschliessend ein Model (als Thread) und fuehrt die + Funktion CopySpelling aus. + ''' + self.file = path + if self.file is "-1": + self.view.changeFrame("StartPage") + else: + if(self.modi == "taktilesBCI"): + self.model = ModellTaktil(self, dll=self.dll) + elif(self.modi == "visuellesBCI"): + self.model = ModellVisuell(self, dll=self.dll) + self.model.setFunktion(self.model.startCopySpelling) + self.model.start() + + def filterXdawn(self): + '''-------------------------------------------------------------------------------------------------- + wird nach dem CopySpelling gestartet. Die Funktion erstellt ein Model (als Thread) und fuehrt die + Funktion trainXDawn aus. + ''' + + if(self.modi == "taktilesBCI"): + self.model = ModellTaktil(self, dll=self.dll) + elif(self.modi == "visuellesBCI"): + self.model = ModellVisuell(self, dll=self.dll) + self.model.setFunktion(self.model.trainXDawn) + self.model.start() + + def filterClassic(self): + '''-------------------------------------------------------------------------------------------------- + wird nach dem xDawn-Training gestartet. Die Funktion erstellt ein Model (als Thread) und fuehrt die + Funktion trainClassifier aus. + ''' + + if(self.modi == "taktilesBCI"): + self.model = ModellTaktil(self, dll=self.dll) + elif(self.modi == "visuellesBCI"): + self.model = ModellVisuell(self, dll=self.dll) + self.model.setFunktion(self.model.trainClassifier) + self.model.start() + + def commandFreeSpelling(self): + '''-------------------------------------------------------------------------------------------------- + startet nach Benutzeraktion das Freespelling: ie Funktion erstellt ein Model (als Thread) und fuehrt die + Funktion freespelling aus. + ''' + print("freespelling") + if(self.modi == "taktilesBCI"): + self.model = ModellTaktil(self, dll=self.dll) + elif(self.modi == "visuellesBCI"): + self.model = ModellVisuell(self, dll=self.dll) + self.model.setFunktion(self.model.freeSpelling) + self.model.start() + + + def commandStop(self): + '''-------------------------------------------------------------------------------------------------- + Wird nach Benutzeraktion aufgerufen und stopt, falls vorhanden, den ablaufenden Thread und schliesst + Openvibe + ''' + if(self.model is not None): + self.addInfoText("Aktion: STOP-Befehl\n") + self.model.stop() + self.model.join() + self.model.killProzess() + self.mode = None + + def stopAcquisitionServer(self): + '''-------------------------------------------------------------------------------------------------- + Wird nur beim schliessen der GUI aufgerufen und stopt und schliesst den Acquisitionserver + ''' + self.acquisitionServer.stop() + self.acquisitionServer.join() + self.acquisitionServer.killAcquisitionServer() + self.acquisitionServer = None + + def stop(self, next=None): + '''-------------------------------------------------------------------------------------------------- + Wird aus dem Modell nach Ablauf oder bei Fehler aufgerufen und stopt den aktuellen Thread. + Anschliessend wird je nach Prozess die naechste Funktion (XDawn-Training oder Classifier) aufgerufen + ''' + print("Stop aus Modell") + self.model.stop() + self.model.join() + self.model.killProzess() + self.mode = None + if(next is not None): + func = self.nexts.get(next) + func() + + + def addInfoText(self,text): + '''-------------------------------------------------------------------------------------------------- + Fuegt dem Infotext den Text hinzu und schreibt es in die Ausgabe + ''' + self.infotext = self.infotext + text + self.view.setInfoText(self.infotext) + + def resetInfo(self): + self.infotext = "" + + def setTitle(self,text): + self.view.setTitleText(text) + + def changeScreen(self, pageName): + self.view.changeFrame(pageName=pageName) + + def getModi(self): + return self.modi + + def getWindowSize(self): + return self.view.getWindowSize() + + + + diff --git a/UIController.pyc b/UIController.pyc new file mode 100644 index 0000000..61b96f7 Binary files /dev/null and b/UIController.pyc differ diff --git a/UIModell.py b/UIModell.py new file mode 100644 index 0000000..4727564 --- /dev/null +++ b/UIModell.py @@ -0,0 +1,180 @@ +'''-------------------------------------------------------------------------------------------------- +Das Model steuert stellt die Modi unabhaengigen Funktionen bereit +''' + +from subprocess import * +from threading import Thread +import time + +class Modell(Thread): + + def __init__(self,c, dll): + Thread.__init__(self) + self.controller = c + self.dll = dll + self.aktiv= True + + def setFunktion(self, func, args=None, kwargs=None): + pass + + def startCopySpelling(self): + pass + + def trainXDawn(self): + pass + + def trainClassifier(self): + pass + + def freeSpelling(self): + pass + + def stop(self): + '''-------------------------------------------------------------------------------------------------- + Die Funktion stop stopt den ablaufenden Thread + ''' + print("stop thread") + self.aktiv = False + + def run(self): + '''-------------------------------------------------------------------------------------------------- + Wird bei Thread.start() aus dem Controller aufgerufen und laeuft ab sobald der Thread destartet wurde + ''' + print("start thread") + #self.aktiv = True + t = Thread(target=self.startAquisitionServer) + t.setDaemon(True) + t.start() + + while self.aktiv: + time.sleep(0.1) + + def killProzessParent(self): + '''-------------------------------------------------------------------------------------------------- + schliesst OpenVibe-Designer + ''' + print('Parent start killing') + pidOV = 0 + items = [] + + prozesse = Popen(["ps", "-e"], stdout=PIPE).communicate()[0].strip() + zeilen = prozesse.split('\n') + for z in zeilen: + if(z.find("openvibe-design") != -1): + z = z.strip() + items = z.split(' ') + pidOV = items[0] + print(pidOV) + if pidOV is not 0: + #kill -TERM veranlasst dem Prozess sich selbst zu beenden (nicht erzwungen) + try: + Popen(["kill", "-TERM", str(pidOV)], stdout=PIPE).communicate() + except: + print("kein killing") + + + print("killed openvibe-designer") + + def killAcquisitionServer(self): + '''-------------------------------------------------------------------------------------------------- + schliesst den Acquisitionserver + ''' + + print('start killing AS') + pid = 0 + items = [] + + prozesse = Popen(["ps", "-e"], stdout=PIPE).communicate()[0].strip() + zeilen = prozesse.split('\n') + for z in zeilen: + if(z.find("openvibe-acquis") != -1): + z = z.strip() + items = z.split(' ') + pid = items[0] + + #kill -TERM veranlasst dem Prozess sich selbst zu beenden (nicht erzwungen) + Popen(["kill", "-TERM", str(pid)], stdout=PIPE).communicate() + + + print("killed openvibe-acquisitionserver") + + + + def startAquisitionServer(self): + '''-------------------------------------------------------------------------------------------------- + startet den Acquisitionserver und steuert die Benutzerausgabe + ''' + + print("start Aquisitionserver") + self.controller.resetInfo() + self.controller.addInfoText('Aquisitionserver -- Bitte starten sie den Server\n') + + command = self.dll.getCommandStartAquisitionServer().split(" ") + process = Popen(command, stdout=PIPE, universal_newlines=True) + + self.openVibeAktiv = True + while True: + output = process.stdout.readline() + print(output.strip()) + x1 = output.find("Connection succeeded") + x2 = output.find("Now acquiring") + x3 = output.find("Stopping the acquisition") + x4 = output.find("Disconnecting") + init = output.find("Loading plugin: Fiddler") + y = output.find("Error") + if(x1 != -1): + self.controller.addInfoText('Aquisitionserver ist verbunden -- Bitte starten Sie den Server\n') + elif(x2 != -1 ): + self.controller.resetInfo() + self.controller.addInfoText("Aquisitionserver gestartet\n") + self.minimizeWindow("server") + elif(x3 != -1 ): + self.controller.addInfoText("AquisitionServer gestoppt -- Bitte starten Sie den Server\n") + self.positionWindow("server") + elif(x4 != -1 ): + self.controller.addInfoText("Verbindung vom Aquisitionserver getrennt!\n") + self.positionWindow("server") + elif(init != -1 ): + time.sleep(1) + self.positionWindow("server") + elif(y != -1 ): + self.controller.addInfoText("Fehler beim Auisitionserver aufgetaucht\n") + if not self.aktiv: + print("stop") + break + + def positionWindow(self, name): + '''-------------------------------------------------------------------------------------------------- + positioniert das Fenster auf der GUI + ''' + print("calls positionWindow") + parameter = self.controller.getWindowSize() + positionX = int(parameter[0]+ int(parameter[3] * 0.05)) + positionY = int(parameter[1]) + int(parameter[2]*0.08) + height = int(parameter[2])*0.55 + width = int(parameter[3])*0.9 + windowID = Popen(["xdotool", "search", "--onlyvisible", "--name", name], stdout=PIPE).communicate()[0].strip() + try: + print(int(windowID)) + Popen(["xdotool", "windowsize", windowID, str(width), str(height)], stdout=PIPE).communicate() + Popen(["xdotool", "windowmove", windowID, str(positionX), str(positionY)], stdout=PIPE).communicate() + Popen(["xdotool", "windowactivate", windowID], stdout=PIPE).communicate()[0].strip() + except: + print("no window") + print(windowID) + self.controller.addInfoText("Fehler: kein Fenster gefunden!") + + def minimizeWindow(self, name): + '''-------------------------------------------------------------------------------------------------- + minimiert das Fenster + ''' + windowID = Popen(["xdotool", "search", "--onlyvisible", "--name", name], stdout=PIPE).communicate()[0].strip() + try: + print(int(windowID)) + Popen(["xdotool", "windowminimize", windowID], stdout=PIPE).communicate() + except: + print("no window") + print(windowID) + self.controller.addInfoText("Fehler: kein Fenster gefunden!") + + diff --git a/UIModell.pyc b/UIModell.pyc new file mode 100644 index 0000000..a4777bc Binary files /dev/null and b/UIModell.pyc differ diff --git a/UIModellTaktil.py b/UIModellTaktil.py new file mode 100644 index 0000000..ce30761 --- /dev/null +++ b/UIModellTaktil.py @@ -0,0 +1,214 @@ +'''-------------------------------------------------------------------------------------------------- +Das taktile Model steuert den Ablauf der aufrufe der Openvibe Funktionen fuer das taktile BCI +noch nicht implementiert da noch kein Programm dafuer +''' + +from subprocess import * +from threading import Thread +import time +from UIModell import * + +class ModellTaktil(Modell): + + def __init__(self,c, dll): + Thread.__init__(self) + Modell.__init__(self, c, dll) + #self.dll = dll + self.aktiv= True + self.openVibeAktiv = False + + def stop(self): + '''-------------------------------------------------------------------------------------------------- + Die Funktion stop stopt den ablaufenden Thread + ''' + print("stop thread") + self.aktiv = False + + def setFunktion(self, func, args=None, kwargs=None): + '''-------------------------------------------------------------------------------------------------- + Mittels dieser Funktion kann die im Thread ablaufende Funktion und deren Argumente eingestellt werden + ''' + self.func = func + self.args = args or [] + self.kwargs = kwargs or {} + + def run(self): + '''-------------------------------------------------------------------------------------------------- + Wird bei Thread.start() aus dem Controller aufgerufen und laeuft ab sobald der Thread destartet wurde + ''' + print("start thread") + #self.aktiv = True + t = Thread(target=self.func, args=self.args, kwargs=self.kwargs) + t.setDaemon(True) + t.start() + + while self.aktiv: + time.sleep(0.1) + + + def startCopySpelling(self): + '''-------------------------------------------------------------------------------------------------- + Holt aus der shared Librarz die Befehle und startet das Copyspelling. Reagiert auf Error oder + beenden. Bei Beenden startet es das XDawnTraining, bei Error wird der Vorgang gestoppt. + ''' + print("start copySpelling") + self.controller.resetInfo() + self.controller.addInfoText('Starten des gefuerten Buchstabierens -- ') + + command = self.dll.getCommandCopyspellingVisuell().split(" ") + process = Popen(command, stdout=PIPE, universal_newlines=True) + + self.openVibeAktiv = True + while True: + output = process.stdout.readline() + print(output.strip()) + x = output.find("schlagwort?") + y = output.find("Error") + if(x != -1): + print("Training finished") + process.terminate() + self.controller.addInfoText('Buchstabieren beendet\n') + self.controller.stop("filterXdawn") + break + elif(y != -1 ): + print("Error occured") + self.controller.changeScreen("StartPage") + self.controller.addInfoText("Fehler beim Buchstabieren aufgetaucht\n") + process.terminate() + self.controller.stop() + break + if not self.aktiv: + print("stop") + break + + + self.controller.stop() + + def trainXDawn(self): + '''-------------------------------------------------------------------------------------------------- + Holt aus der shared Library die Befehle und startet das XDawnTraining. Reagiert auf Error oder + die Ausgabe das das Training beendet wurde. Bei Beenden startet es das ClassifierTraining, bei Error wird der Vorgang gestoppt. + ''' + print("start training Xdawn") + self.controller.addInfoText('Starten des xDawn-Trainings -- ') + command = self.dll.getCommandXDawn().split(" ") + process = Popen(command, stdout=PIPE, universal_newlines=True) + + self.openVibeAktiv = True + while self.aktiv: + output = process.stdout.readline() + print(output.strip()) + x = output.find("Training finished and saved") + y = output.find("Error") + if(x != -1): + print("Training finished") + process.terminate() + self.controller.addInfoText('Training beendet\n') + self.controller.stop("filterClassic") + break + elif(y != -1 ): + print("Error occured") + self.controller.changeScreen("StartPage") + self.controller.addInfoText("Fehler beim XDawn Training aufgetaucht\n") + self.controller.stop() + process.terminate() + break + if not self.aktiv: + print("stop") + break + + self.controller.stop() + + #self.controller.filterClassic() + + + def trainClassifier(self): + '''-------------------------------------------------------------------------------------------------- + Holt aus der shared Library die Befehle und startet das ClassifierTraining. Reagiert auf Error oder + die Ausgabe das das Training beendet wurde. Bei Beenden startet es das speichern der Daten, bei Error wird der Vorgang gestoppt. + ''' + print("start training Classifier") + self.controller.addInfoText("Starten des Classifier-Trainings -- ") + + command = self.dll.getCommandClassifier().split(" ") + process = Popen(command, stdout=PIPE, universal_newlines=True) + + self.openVibeAktiv = True + counter = 0 + while True: + output = process.stdout.readline() + print(output.strip()) + x = output.find("aka Classifier trainer") + accuracy = output.find("Training set accuracy is") + y = output.find("Error") + if(x != -1): + counter = counter +1 + #counter = 18 + if(counter >= 17): + print("Training finished") + self.controller.addInfoText('Training beendet\n') + process.terminate() + self.controller.stop("save") + break + elif(y != -1 ): + print("Error occured") + self.controller.changeScreen("StartPage") + self.controller.addInfoText("Fehler beim Classifier Training aufgetaucht\n") + process.terminate() + break + elif(accuracy != -1): + print("ACCURACY" + output) + if not self.aktiv: + print("stop") + break + + self.controller.changeScreen("StartPage") + self.controller.stop() + + def freeSpelling(self): + '''-------------------------------------------------------------------------------------------------- + Holt aus der shared Library die Befehle und startet das Freespelling. Reagiert auf Error oder + beenden. Daraufhin wird der Vorgang gestoppt. + ''' + print("start freeSpelling") + self.controller.resetInfo() + self.controller.addInfoText('Starten des freien Buchstabierens -- ') + command = self.dll.getCommandFreespellingVisuell().split(" ") + process = Popen(command, stdout=PIPE, universal_newlines=True) + self.openVibeAktiv = True + while True: + output = process.stdout.readline() + print(output.strip()) + y = output.find("Error") + x = output.find("Schlagwort") + if(x != -1): + print("End Spelling") + process.terminate() + self.controller.addInfoText('Buchstabieren beendet\n') + self.controller.changeScreen("StartPage") + self.controller.stop() + break + elif(y != -1 ): + print("Error occured") + self.controller.changeScreen("StartPage") + self.controller.addInfoText("Fehler beim Buchstabieren aufgetaucht\n") + process.terminate() + self.controller.stop() + break + if not self.aktiv: + print("stop") + break + + self.controller.changeScreen("StartPage") + self.controller.stop() + + def killProzess(self): + '''-------------------------------------------------------------------------------------------------- + Ruft den Parent auf, dass Openvibe falls es noch laeuft geschlossen wird + ''' + if(self.openVibeAktiv): + self.openVibeAktiv = False + self.killProzessParent() + + + diff --git a/UIModellTaktil.pyc b/UIModellTaktil.pyc new file mode 100644 index 0000000..be5b006 Binary files /dev/null and b/UIModellTaktil.pyc differ diff --git a/UIModellVisuell.py b/UIModellVisuell.py new file mode 100644 index 0000000..299ff0d --- /dev/null +++ b/UIModellVisuell.py @@ -0,0 +1,225 @@ +'''-------------------------------------------------------------------------------------------------- +Das Visuelle Model steuert den Ablauf der aufrufe der Openvibe Funktionen fuer das visuelle BCI +''' + +from subprocess import * +from threading import Thread +import time + +from UIModell import Modell + +class ModellVisuell(Modell): + + def __init__(self,c, dll): + Thread.__init__(self) + Modell.__init__(self, c, dll) + self.aktiv= True + self.openVibeAktiv = False + + def stop(self): + '''-------------------------------------------------------------------------------------------------- + Die Funktion stop stopt den ablaufenden Thread + ''' + print("stop thread") + self.aktiv = False + + def setFunktion(self, func, args=None, kwargs=None): + '''-------------------------------------------------------------------------------------------------- + Mittels dieser Funktion kann die im Thread ablaufende Funktion und deren Argumente eingestellt werden + ''' + self.func = func + self.args = args or [] + self.kwargs = kwargs or {} + + def run(self): + '''-------------------------------------------------------------------------------------------------- + Wird bei Thread.start() aus dem Controller aufgerufen und laeuft ab sobald der Thread destartet wurde + ''' + print("start thread") + #self.aktiv = True + t = Thread(target=self.func, args=self.args, kwargs=self.kwargs) + t.setDaemon(True) + t.start() + + while self.aktiv: + time.sleep(0.1) + + + def startCopySpelling(self): + '''-------------------------------------------------------------------------------------------------- + Holt aus der shared Librarz die Befehle und startet das Copyspelling. Reagiert auf Error oder + beenden. Bei Beenden startet es das XDawnTraining, bei Error wird der Vorgang gestoppt. + Positioniert die visuelle Matrix. + ''' + print("start copySpelling") + self.controller.resetInfo() + self.controller.addInfoText('Starten des gefuerhten Buchstabierens -- ') + command = self.dll.getCommandCopyspellingVisuell().split(" ") + process = Popen(command, stdout=PIPE, universal_newlines=True) + + self.openVibeAktiv = True + while True: + output = process.stdout.readline() + print(output.strip()) + x = output.find("Application terminated") + y = output.find("Error") + z = output.find("Initialization") + if(x != -1): + print("Training finished") + process.terminate() + self.controller.addInfoText('Buchstabieren beendet\n') + self.controller.stop("filterXdawn") + break + elif(y != -1 ): + print("Error occured") + self.controller.changeScreen("StartPage") + self.controller.addInfoText("Fehler beim Buchstabieren aufgetaucht\n") + process.terminate() + self.controller.stop() + break + elif(z != -1): + print("Initiation finisched") + time.sleep(1) + self.positionWindow("p300") + self.minimizeWindow("stimulator") + if not self.aktiv: + print("stop") + break + #self.controller.stop() + + def trainXDawn(self): + '''-------------------------------------------------------------------------------------------------- + Holt aus der shared Library die Befehle und startet das XDawnTraining. Reagiert auf Error oder + die Ausgabe das das Training beendet wurde. Bei Beenden startet es das ClassifierTraining, bei Error wird der Vorgang gestoppt. + ''' + print("start training Xdawn") + self.controller.addInfoText('Starten des XDawn/Trainings -- ') + command = self.dll.getCommandXDawn().split(" ") + process = Popen(command, stdout=PIPE, universal_newlines=True) + + self.openVibeAktiv = True + while self.aktiv: + output = process.stdout.readline() + print(output.strip()) + x = output.find("Training finished and saved") + y = output.find("Error") + if(x != -1): + print("Training finished") + process.terminate() + self.controller.addInfoText('Beenden des Trainings\n') + self.controller.stop("filterClassic") + break + elif(y != -1 ): + print("Error occured") + self.controller.changeScreen("StartPage") + self.controller.addInfoText("Fehler beim XDawn Training aufgetaucht\n") + self.controller.stop() + process.terminate() + break + if not self.aktiv: + print("stop") + break + + #self.controller.stop() + + def trainClassifier(self): + '''-------------------------------------------------------------------------------------------------- + Holt aus der shared Library die Befehle und startet das ClassifierTraining. Reagiert auf Error oder + die Ausgabe das das Training beendet wurde. Bei Beenden startet es das speichern der Daten, bei Error wird der Vorgang gestoppt. + ''' + print("start training Classifier") + self.controller.addInfoText("Starten Classifier-Trainings -- ") + command = self.dll.getCommandClassifier().split(" ") + process = Popen(command, stdout=PIPE, universal_newlines=True) + + self.openVibeAktiv = True + counter = 0 + while True: + output = process.stdout.readline() + print(output.strip()) + x = output.find("aka Classifier trainer") + accuracy = output.find("Training set accuracy is") + y = output.find("Error") + if(x != -1): + counter = counter +1 + #counter = 18 + if(counter >= 17): + print("Training finished") + self.controller.addInfoText('Beenden des Training\n') + process.terminate() + self.controller.stop("save") + break + elif(y != -1 ): + print("Error occured") + self.controller.changeScreen("StartPage") + self.controller.addInfoText("Fehler beim Classifier Training aufgetaucht\n") + process.terminate() + break + elif(accuracy != -1): + print("ACCURACY" + output) + if not self.aktiv: + print("stop") + break + + self.controller.changeScreen("StartPage") + self.controller.stop() + + def freeSpelling(self): + '''-------------------------------------------------------------------------------------------------- + Holt aus der shared Library die Befehle und startet das Freespelling. Reagiert auf Error oder + beenden. Daraufhin wird der Vorgang gestoppt. Positioniert die visuelle Matrix. + ''' + print("start freeSpelling") + self.controller.resetInfo() + self.controller.addInfoText('Starten des freien Buchstabierens -- ') + + command = self.dll.getCommandFreespellingVisuell().split(" ") + process = Popen(command, stdout=PIPE, universal_newlines=True) + + self.openVibeAktiv = True + while True: + output = process.stdout.readline() + print(output.strip()) + y = output.find("Error") + x = output.find("Schlagwort") + z = output.find("Initialization") + if(x != -1): + print("End Spelling") + process.terminate() + self.controller.addInfoText('Buchstabieren beendet\n') + self.controller.changeScreen("StartPage") + self.controller.stop() + break + elif(y != -1 ): + print("Error occured") + self.controller.changeScreen("StartPage") + self.controller.addInfoText("Fehler beim Buchstabieren aufgetaucht\n") + process.terminate() + self.controller.stop() + break + elif(z != -1): + print("Initiation finisched") + time.sleep(1) + self.positionWindow("p300") + self.minimizeWindow("stimulator") + if not self.aktiv: + print("stop") + break + + self.controller.changeScreen("StartPage") + self.controller.stop() + + def killProzess(self): + '''-------------------------------------------------------------------------------------------------- + Ruft den Parent auf, dass Openvibe falls es noch laeuft geschlossen wird + ''' + if(self.openVibeAktiv): + self.openVibeAktiv = False + self.killProzessParent() + + + + + + + \ No newline at end of file diff --git a/UIModellVisuell.pyc b/UIModellVisuell.pyc new file mode 100644 index 0000000..e91a99f Binary files /dev/null and b/UIModellVisuell.pyc differ diff --git a/UIView.pyc b/UIView.pyc new file mode 100644 index 0000000..26e74de Binary files /dev/null and b/UIView.pyc differ diff --git a/UIViewTKinter.py b/UIViewTKinter.py new file mode 100644 index 0000000..29cfc5b --- /dev/null +++ b/UIViewTKinter.py @@ -0,0 +1,267 @@ +'''-------------------------------------------------------------------------------------------------- +Die View bildet die Oberflaeche ab. +Sie ist in 3 Sektoren Top, Main und ButtonFrame unterteilt. Der TopFrame beihnahltet die Taskleiste, +der Button Frame gibt Informationen raus. Im Main Frame sind die Buttons yu starten und stoppen der +Buchstabierungen. HIerfuer sind extra Seiten erstellt, die beliebig, je nach Situation ausgetauscht +werden koennen +''' + +try: + from Tkinter import * #Fuer Python 2.7 + import tkFileDialog as fd +except ImportError: #Fuer Python >3 + from tkinter import * + from tkinter import filedialog as fd + +from UIController import * + + + +class View(Tk): + def __init__(self, c, path_default, *args, **kwargs): + '''-------------------------------------------------------------------------------------------------- + In der Init wird das Lazout gesetyt und die Funktionen yur erstellung der Frames aufgerufen, + zudem wird dem schliesen des Fensters sowie den anpassen der Groesse andere Funktionen hinterlegt + ''' + Tk.__init__(self, *args, **kwargs) + self.controller = c + self.PATH_DEFAULT = path_default + self.title("Visuelles Buchstabieren") + self.h = 1000 + self.w = 2000 + self.geometry('{}x{}'.format(self.w,self.h)) + self.faktor = [(0.073),(0.727), (0.2)] + #self.resizable(height=False, width= False) + self.layout = { + "background": "#00001E", + "backgroundBtn": "#1C86EE", + "fontColor": "#FFFFFF", + "backgroundBar": "#00002E", + "font": ('Calibri', 20, 'bold'), + "fontSmall": ('Calibri', 14, 'bold'), + "fontInfo": ('Calibri', 25) + } + + self.createTopFrame() + self.createMainFrame() + self.createBottomFrame() + + self.bind("", self.adjustSize) + self.protocol("WM_DELETE_WINDOW", self.onClosing) + + + def changeFrame(self, pageName): + '''-------------------------------------------------------------------------------------------------- + Setzt dem Frame passend zum pageName in den Vordergrund + ''' + frame = self.frames[pageName] + frame.tkraise() + + def adjustSize(self, event): + '''-------------------------------------------------------------------------------------------------- + passt nach Faktoren die einyelnen Seitenteile der jeweiligen Frame Groesse an + ''' + if(str(event.widget) =="."): + self.h = event.height + self.w = event.width + self.topFrame.configure(height=(self.h*self.faktor[0]), width=self.w) + self.mainFrame.configure(height=(self.h*self.faktor[1]), width=self.w) + self.bottomFrame.configure(height=(self.h*self.faktor[2]), width=self.w) + self.container.configure(height=(self.h*self.faktor[1]), width=self.w) + for f in self.frames: + self.frames[f].configure(height=(self.h*self.faktor[1]), width=self.w) + self.frames[f].adjustSize(height=(self.h*self.faktor[1]), width=self.w) + + + def onClosing(self): + '''-------------------------------------------------------------------------------------------------- + Stoppt alle laufenden Threads und schliesst OpenVibe und den Aquisitionserver bevor sich das Fenster + schliesst + ''' + print("closing") + self.controller.commandStop() + self.controller.stopAcquisitionServer() + print("destroy") + self.destroy() + + + def createTopFrame(self): + '''-------------------------------------------------------------------------------------------------- + Erstellt die Buttons und Textfelder fuer die Taskleiste und positionier diese im Frame + ''' + self.topFrame = Frame(self, bg=self.layout["backgroundBar"], height=50, width=500) + self.changeBtn = Button(self.topFrame, text="Wechsel zu taktilen BCI", command=lambda: self.controller.actionPerformed("wechsel"), height=3, width = 30, font=self.layout["fontSmall"], bg=self.layout["backgroundBtn"], fg=self.layout["fontColor"]) + self.saveBtn = Button(self.topFrame, text="Auswaehlen der Datei", command=lambda: self.controller.actionPerformed("speicherort"), height=3, width = 30, font=self.layout["fontSmall"], bg=self.layout["backgroundBtn"], fg=self.layout["fontColor"]) + #self.setBtn = Button(self.topFrame, text="Auswaehlen der Datei", command=lambda: self.controller.actionPerformed("setFile"), height=2, width = 25, font=self.layout["fontSmall"], bg=self.layout["backgroundBtn"], fg=self.layout["fontColor"]) + self.toplabel = Label(self.topFrame, text="visuelles BCI", font=self.layout["font"], bg=self.layout["backgroundBar"], fg=self.layout["fontColor"], ) + + self.topFrame.grid(column=0, row=0) + self.topFrame.grid_propagate(0) + self.topFrame.pack_propagate(0) + + self.changeBtn.grid(column=0, row=0, padx=10,pady=5) + self.saveBtn.grid(column=1, row=0, padx=10, pady=5) + #self.setBtn.grid(column=2, row=0, padx=10, pady=5) + self.toplabel.grid(column=2, row=0, padx=100, pady=2) + + def createMainFrame(self): + '''-------------------------------------------------------------------------------------------------- + Erstellt und postioniert einen Container als Platzhalter fuer die verschiedenen Seiten. Anscliessend + erstellt es die verschiedenen Seiten und speicher diese in eine Liste + ''' + self.mainFrame = Frame(self, bg=self.layout["background"], height=250, width=500) + self.mainFrame.grid(column=0, row=1) + self.mainFrame.pack_propagate(0) + + self.container = Frame(self.mainFrame, bg=self.layout["background"], height=250, width=500) + self.container.pack(side="top", fill="both", expand = True) + self.container.pack_propagate(0) + self.container.grid_propagate(0) + + self.frames = {} + for F in (StartPage, WorkingPageTaktil, WorkingPageVisuell): + page_name = F.__name__ + frame = F(parent=self.container, controller=self.controller, layout=self.layout) + self.frames[page_name] = frame + frame.grid(row=0, column=0, sticky="nsew") + + self.changeFrame("StartPage") + + def createBottomFrame(self): + '''-------------------------------------------------------------------------------------------------- + Erstellt und positioniert ein Label fuer die ganzen Informationen + ''' + self.bottomFrame = Frame(self, bg=self.layout["backgroundBar"], height=100, width=500) + self.bottomlabel = Label(self.bottomFrame, text="Hier stehen Infos\nGanz viele", justify='left', font=self.layout["fontInfo"], bg=self.layout["backgroundBar"], fg=self.layout["fontColor"]) + + self.bottomFrame.grid(column=0, row=2) + self.bottomFrame.pack_propagate(0) + self.bottomFrame.grid_propagate(0) + + self.bottomlabel.grid(padx=5,pady=5) + + def setInfoText(self, text): + self.bottomlabel['text'] = text + + def setTitleText(self,text): + self.title(text) + self.toplabel["text"] = text + + def setChangeBtnText(self,text): + self.changeBtn["text"] = text + + def openfiledialog(self): + path = self.PATH_DEFAULT + #file = fd.askopenfilename(initialdir=path) + file = fd.askdirectory(initialdir=path) + return file + + def savefiledialog(self): + self.dialog = Tk() + l = Label(self.dialog, text="Bitte geben Sie einen Speichernamen ein:") + eingabefeld = Entry(self.dialog) + okBtn = Button(self.dialog, text="OK", command=lambda:self.okBtn(eingabefeld.get())) + l.pack() + eingabefeld.pack() + okBtn.pack() + + self.dialog.protocol("WM_DELETE_WINDOW", self.closeDialog) + self.dialog.mainloop() + + def okBtn(self, text): + path = self.PATH_DEFAULT + "/" + text + print(path) + self.controller.copyspelling(path) + self.dialog.destroy() + + def closeDialog(self): + self.controller.copyspelling("-1") + self.dialog.destroy() + + def getWindowSize(self): + return [self.winfo_x(), self.winfo_y(), self.winfo_height(), self.winfo_width()] + + +class StartPage(Frame): + '''-------------------------------------------------------------------------------------------------- + Bildet die Seite in der die Aktionen ausgesucht werden koennen. Beihaltet 2 Buttons einen zum starten + des freien Buchstabierens und einen yum starten des gefuerten Buchstabierens + ''' + def __init__(self, parent, controller, layout): + self.layout = layout + + Frame.__init__(self, parent, height=250, width=500, bg=self.layout["background"]) + self.grid_propagate(0) + self.pack_propagate(0) + self.controller = controller + + self.container = Frame(self, bg=self.layout["background"], height=250, width=500) + self.btnFrame = Frame(self.container, bg=self.layout["background"], height=250, width=250) + + self.container.columnconfigure(0, weight=1) # Set weight to row and + self.container.rowconfigure(0, weight=1) # column where the widget is + self.container.grid_propagate(0) + self.container.pack_propagate(0) + + self.container.pack() + self.btnFrame.grid() + + testBtn = Button(self.btnFrame, text="gefuehrtes Buchstabieren", command=lambda: self.controller.actionPerformed("copySpelling"), height=6, width = 20, font=self.layout["font"], bg=self.layout["backgroundBtn"], fg=self.layout["fontColor"]) + #testBtn = Button(self.btnFrame, text="copySpelling", command=lambda: self.controller.actionPerformed("test"), height=6, width = 20, font=self.layout["font"], bg=self.layout["backgroundBtn"], fg=self.layout["fontColor"]) + testBtn.grid(row=0,column=0, padx=25,pady=25) + + freeSpellingBtn = Button(self.btnFrame, text="freies Buchstabieren", command=lambda: self.controller.actionPerformed("freeSpelling"), height=6, width = 20, font=self.layout["font"], bg=self.layout["backgroundBtn"], fg=self.layout["fontColor"]) + freeSpellingBtn.grid(row=0, column=1, padx=25,pady=25) + + def adjustSize(self, height, width): + self.container.configure(height=height, width= width) + self.btnFrame.configure(height=(height*4)/5, width= width/2) + +class WorkingPageTaktil(Frame): + '''-------------------------------------------------------------------------------------------------- + Bildet die Seite nach Auswahl einer Aktion. Beihaltet einen mittig plazierten Buttons zum stoppen + des ablaufenden Vorgang + ''' + def __init__(self, parent, controller, layout): + self.layout = layout + + Frame.__init__(self, parent, height=250, width=500, bg=self.layout["background"]) + self.controller = controller + + + self.columnconfigure(0, weight=1) # Set weight to row and + self.rowconfigure(0, weight=1) # column where the widget is + + stopBtn = Button(self, text="stop", command=lambda: self.controller.actionPerformed("stop"), height=4, width = 15, font=self.layout["font"], bg=self.layout["backgroundBtn"], fg=self.layout["fontColor"]) + stopBtn.grid() + + def adjustSize(self, height, width): + pass + +class WorkingPageVisuell(Frame): + '''-------------------------------------------------------------------------------------------------- + Bildet die Seite nach Auswahl einer Aktion. Beihaltet einen mittig unten plazierten Buttons zum + stoppen des ablaufenden Vorgang + ''' + def __init__(self, parent, controller, layout): + self.layout = layout + + Frame.__init__(self, parent, height=250, width=500, bg=self.layout["background"]) + self.controller = controller + self.grid_propagate(0) + self.pack_propagate(0) + + self.windowFrame = Frame(self, height=200, width=500, bg=self.layout["background"]) + self.windowFrame.grid(column=0, row=0) + + self.buttonFrame = Frame(self, height=200, width=500, bg=self.layout["background"]) + self.buttonFrame.grid(column=0, row=1) + self.buttonFrame.columnconfigure(0, weight=1) # Set weight to row and + self.buttonFrame.rowconfigure(0, weight=1) # column where the widget is + + stopBtn = Button(self.buttonFrame, text="stop", command=lambda: self.controller.actionPerformed("stop"), height=1, width = 15, font=self.layout["font"], bg=self.layout["backgroundBtn"], fg=self.layout["fontColor"]) + stopBtn.grid() + + def adjustSize(self, height, width): + self.windowFrame.configure(height=(height*4)/5, width= width) + self.buttonFrame.configure(height=(height)/10, width= width) \ No newline at end of file diff --git a/UIViewTKinter.pyc b/UIViewTKinter.pyc new file mode 100644 index 0000000..28a60d0 Binary files /dev/null and b/UIViewTKinter.pyc differ diff --git a/dll b/dll new file mode 100755 index 0000000..e88d2e0 Binary files /dev/null and b/dll differ diff --git a/dll.cpp b/dll.cpp new file mode 100644 index 0000000..651cbe4 --- /dev/null +++ b/dll.cpp @@ -0,0 +1,146 @@ +#include +#include +using namespace std; + +extern "C"{ + + string PATH_OV = "meta/dist/Release/openvibe-designer.sh"; + string PATH_AquisitionServer = "meta/dist/Release/openvibe-acquisition-server.sh"; + string PATH_FILES = "Projekte/OpenViBE_visual_BCI-master/openvibe_visual_bci/"; + string pathOVFile = "Projekte/OpenViBE_visual_BCI-master/openvibe_visual_bci/signals/p300-xdawn-train2.ov"; + string pathClassifierCFG = "Projekte/OpenViBE_visual_BCI-master/openvibe_visual_bci/cfg/p300-classifier.cfg"; + string pathSpatialCFG = "Projekte/OpenViBE_visual_BCI-master/openvibe_visual_bci/cfg/p300-spatial-filter.cfg"; + string PATH_DEFAULT = "Projekte/OpenViBE_visual_BCI-master/openvibe_visual_bci/datasets"; + + string fileCopySpellingTaktil = "p300-visual-1-acquisition.xml"; + string fileCopySpellingVisuell = "p300-visual-1-acquisition.xml"; + string fileXDawnTraining = "p300-visual-2-train-xDAWN.xml"; + string fileClassifierTraining = "p300-visual-3-train-classifier.xml"; + string filefreeSpellingTaktil = "p300-visual-4-online.xml"; + string filefreeSpellingVisuell = "p300-visual-4-online.xml"; + + string command = "bash"; + string nogui = "--no-gui"; + string play = "--play"; + + + char* getCommandPS(){ + string s = ""; + s = s.append("ps").append(" ").append("-e"); + char char_array[s.length()+1]; + strcpy(char_array, s.c_str()); + char* s_convert = char_array; + return s_convert; + } + + char* getCommandFreespellingTaktil() + { + string s = ""; + s = s.append(command).append(" ").append(PATH_OV).append(" ").append( play).append(" ").append(PATH_FILES).append(filefreeSpellingTaktil).append(" ").append(nogui); + char char_array[s.length()+1]; + strcpy(char_array, s.c_str()); + char* s_convert = char_array; + return s_convert; + } + + char* getCommandFreespellingVisuell() + { + string s = ""; + s = s.append(command).append(" ").append(PATH_OV).append(" ").append( play).append(" ").append(PATH_FILES).append(filefreeSpellingVisuell).append(" ").append(nogui); + char char_array[s.length()+1]; + strcpy(char_array, s.c_str()); + char* s_convert = char_array; + return s_convert; + } + + char* getCommandCopyspellingTaktil() + { + string s = ""; + s = s.append(command).append(" ").append(PATH_OV).append(" ").append( play).append(" ").append(PATH_FILES).append(fileCopySpellingTaktil).append(" ").append(nogui); + char char_array[s.length()+1]; + strcpy(char_array, s.c_str()); + char* s_convert = char_array; + return s_convert; + } + + char* getCommandCopyspellingVisuell() + { + string s = ""; + s = s.append(command).append(" ").append(PATH_OV).append(" ").append( play).append(" ").append(PATH_FILES).append(fileCopySpellingVisuell).append(" ").append(nogui); + char char_array[s.length()+1]; + strcpy(char_array, s.c_str()); + char* s_convert = char_array; + return s_convert; + } + + char* getCommandXDawn() + { + string s = ""; + s = s.append(command).append(" ").append(PATH_OV).append(" ").append( play).append(" ").append(PATH_FILES).append(fileXDawnTraining).append(" ").append(nogui); + char char_array[s.length()+1]; + strcpy(char_array, s.c_str()); + char* s_convert = char_array; + return s_convert; + } + + char* getCommandClassifier() + { + string s = ""; + s = s.append(command).append(" ").append(PATH_OV).append(" ").append( play).append(" ").append(PATH_FILES).append(fileClassifierTraining).append(" ").append(nogui); + char char_array[s.length()+1]; + strcpy(char_array, s.c_str()); + char* s_convert = char_array; + return s_convert; + } + + char* getCommandStartAquisitionServer() + { + string s = ""; + s = s.append(command).append(" ").append(PATH_AquisitionServer); + char char_array[s.length()+1]; + strcpy(char_array, s.c_str()); + char* s_convert = char_array; + return s_convert; + } + + char* getDefaultPath() + { + string s = PATH_DEFAULT; + char char_array[s.length()+1]; + strcpy(char_array, s.c_str()); + char* s_convert = char_array; + return s_convert; + } + + char* getPathOVFile() + { + string s = pathOVFile; + char char_array[s.length()+1]; + strcpy(char_array, s.c_str()); + char* s_convert = char_array; + return s_convert; + } + + char* getSpatialCFGFile() + { + string s = pathSpatialCFG; + char char_array[s.length()+1]; + strcpy(char_array, s.c_str()); + char* s_convert = char_array; + return s_convert; + } + + char* getClassifierCFGFile() + { + string s = pathClassifierCFG; + char char_array[s.length()+1]; + strcpy(char_array, s.c_str()); + char* s_convert = char_array; + return s_convert; + } +} + + + + + diff --git a/dll.so b/dll.so new file mode 100755 index 0000000..8a57b16 Binary files /dev/null and b/dll.so differ diff --git a/gui b/gui new file mode 100755 index 0000000..5d5d671 Binary files /dev/null and b/gui differ diff --git a/gui.py b/gui.py new file mode 100644 index 0000000..a1debe7 --- /dev/null +++ b/gui.py @@ -0,0 +1,8 @@ +'''-------------------------------------------------------------------------------------------------- +In dem File wird eine Instany des Controllers erstellt. Der Controller ist die Schnittstelle +zwischen GUI und Modell und koordiniert den Ablauf und die Erstellung der GUI +''' + +from UIController import * + +controller = Controller() diff --git a/gui.spec b/gui.spec new file mode 100644 index 0000000..2d4545c --- /dev/null +++ b/gui.spec @@ -0,0 +1,33 @@ +# -*- mode: python ; coding: utf-8 -*- + +block_cipher = None + + +a = Analysis(['gui.py'], + pathex=['/home/ubuntu/Desktop/BCIProjekt'], + binaries=[], + datas=[], + hiddenimports=[], + hookspath=[], + runtime_hooks=[], + excludes=[], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=block_cipher, + noarchive=False) +pyz = PYZ(a.pure, a.zipped_data, + cipher=block_cipher) +exe = EXE(pyz, + a.scripts, + a.binaries, + a.zipfiles, + a.datas, + [], + name='gui', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=True ) diff --git a/script.sh b/script.sh new file mode 100644 index 0000000..3d8e279 --- /dev/null +++ b/script.sh @@ -0,0 +1,2 @@ +sudo apt-get install python-tk +sudo apt-get install xdotool diff --git a/test.py b/test.py new file mode 100644 index 0000000..ab20c66 --- /dev/null +++ b/test.py @@ -0,0 +1,80 @@ + +from subprocess import * +from threading import Thread +import time + +class Modell(Thread): + + def __init__(self): + Thread.__init__(self) + self.aktiv= True + + self.aktiv2 = True + + def stop(self): + print("stop thread") + self.aktiv = False + + def setFunktion(self, func, args=None, kwargs=None): + self.func = func + self.args = args or [] + self.kwargs = kwargs or {} + + def run(self): + print("start thread") + #self.aktiv = True + t = Thread(target=self.func, args=self.args, kwargs=self.kwargs) + t.setDaemon(True) + t.start() + + while self.aktiv: + time.sleep(0.1) + + def counter(self): + n = 0 + while self.aktiv2: + print(n) + time.sleep(0.1) + n = n+1 + + if not self.aktiv2: + print("stop") + break + + def stop2(self): + self.aktiv2 = False + #self.aktiv = False + + def test(self): + command = ["bash", "meta/dist/Release/openvibe-designer.sh", "--play", "Projekte/OpenViBE_visual_BCI-master/openvibe_visual_bci/p300-visual-1-acquisition.xml", "--no-gui"] + process = Popen(command, stdout=PIPE, universal_newlines=True) + while self.aktiv2: + output = process.stdout.readline() + print(output.strip()) + x = output.find("Application terminated") + y = output.find("Error") + z = output.find("Initialization") + if(x != -1): + print("Training finished") + process.terminate() + break + elif(y != -1 ): + process.terminate() + break + if not self.aktiv: + print("stop") + break + + +m = Modell() +m.setFunktion(m.test) +m.start() +time.sleep(2) +m.stop() +m.join() +while True: + pass + + + +