#!/usr/bin/env xdg-open | |||||
[Desktop Entry] | |||||
Version=1.0 | |||||
Type=Application | |||||
Terminal=false | |||||
Icon[C]=/home/ubuntu/Downloads/icon.ico | |||||
Name[C]=BCI | |||||
Exec=/home/ubuntu/Desktop/BCIProjekt/start.sh | |||||
Name=BCI | |||||
Icon=/home/ubuntu/Downloads/icon.ico |
'''-------------------------------------------------------------------------------------------------- | |||||
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_visuell()) | |||||
self.modi = "visuellesBCI" | |||||
self.pathOVFile = self.dll.getPathOVFile_visuell() | |||||
self.pathSpatialCfg = self.dll.getSpatialCFGFile_visuell() | |||||
self.pathClassifierCfg = self.dll.getClassifierCFGFile_visuell() | |||||
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_taktil.argtypes = [] | |||||
self.dll.getCommandXDawn_taktil.restype = ctypes.c_char_p | |||||
self.dll.getCommandXDawn_visuell.argtypes = [] | |||||
self.dll.getCommandXDawn_visuell.restype = ctypes.c_char_p | |||||
self.dll.getCommandClassifier_visuell.argtypes = [] | |||||
self.dll.getCommandClassifier_visuell.restype = ctypes.c_char_p | |||||
self.dll.getCommandClassifier_taktil.argtypes = [] | |||||
self.dll.getCommandClassifier_taktil.restype = ctypes.c_char_p | |||||
self.dll.getDefaultPath_visuell.argtypes = [] | |||||
self.dll.getDefaultPath_visuell.restype = ctypes.c_char_p | |||||
self.dll.getDefaultPath_taktil.argtypes = [] | |||||
self.dll.getDefaultPath_taktil.restype = ctypes.c_char_p | |||||
self.dll.getPathOVFile_visuell.argtypes = [] | |||||
self.dll.getPathOVFile_visuell.restype = ctypes.c_char_p | |||||
self.dll.getSpatialCFGFile_visuell.argtypes = [] | |||||
self.dll.getSpatialCFGFile_visuell.restype = ctypes.c_char_p | |||||
self.dll.getClassifierCFGFile_visuell.argtypes = [] | |||||
self.dll.getClassifierCFGFile_visuell.restype = ctypes.c_char_p | |||||
self.dll.getPathOVFile_taktil.argtypes = [] | |||||
self.dll.getPathOVFile_taktil.restype = ctypes.c_char_p | |||||
self.dll.getSpatialCFGFile_taktil.argtypes = [] | |||||
self.dll.getSpatialCFGFile_taktil.restype = ctypes.c_char_p | |||||
self.dll.getClassifierCFGFile_taktil.argtypes = [] | |||||
self.dll.getClassifierCFGFile_taktil.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.view.setDefaultPath(self.dll.getDefaultPath_visuell()) | |||||
self.pathOVFile = self.dll.getPathOVFile_visuell() | |||||
self.pathSpatialCfg = self.dll.getSpatialCFGFile_visuell() | |||||
self.pathClassifierCfg = self.dll.getClassifierCFGFile_visuell() | |||||
self.modi = "visuellesBCI" | |||||
elif(self.modi == "visuellesBCI"): | |||||
self.setTitle("taktiles BCI") | |||||
self.view.setChangeBtnText("Wechsel zu visuellen BCI") | |||||
self.view.setDefaultPath(self.dll.getDefaultPath_taktil()) | |||||
self.pathOVFile = self.dll.getPathOVFile_taktil() | |||||
self.pathSpatialCfg = self.dll.getSpatialCFGFile_taktil() | |||||
self.pathClassifierCfg = self.dll.getClassifierCFGFile_taktil() | |||||
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) | |||||
if not os.path.exists(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")) | |||||
self.changeScreen("StartPage") | |||||
#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 | |||||
print(path) | |||||
if self.file == "-1": | |||||
print("kein gueltiger Pfad") | |||||
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. | |||||
''' | |||||
print("filterXDawn-Controller -Modi: " + self.modi) | |||||
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() | |||||
'''-------------------------------------------------------------------------------------------------- | |||||
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] | |||||
if pid is not 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!") | |||||
'''-------------------------------------------------------------------------------------------------- | |||||
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 * | |||||
import re | |||||
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.getCommandCopyspellingTaktil().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") | |||||
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_taktil() #.split(" ") | |||||
print("Command: " + command) | |||||
command = command.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_taktil().split(" ") | |||||
process = Popen(command, stdout=PIPE, universal_newlines=True) | |||||
self.openVibeAktiv = True | |||||
counter = 0 | |||||
acc = 0 | |||||
while True: | |||||
output = process.stdout.readline() | |||||
print(output.strip()) | |||||
x = output.find("aka Classifier trainer") | |||||
accuracy = output.find("Cross-validation test 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 (' + acc + ')\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 | |||||
if(accuracy != -1): | |||||
#print("Output:") | |||||
#print(output) | |||||
ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])') | |||||
test = output.encode("windows-1252").decode("utf-8") | |||||
i = len("Cross-validation test") | |||||
#print(output[accuracy:accuracy+i+12]) | |||||
#print(test[accuracy+i+12:accuracy+i+40].strip()) | |||||
acc_s = test[accuracy+i:accuracy+i+41].strip() | |||||
acc = ansi_escape.sub('', acc_s) | |||||
print(acc) | |||||
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.getCommandFreespellingTaktil().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("Application terminated") | |||||
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() | |||||
'''-------------------------------------------------------------------------------------------------- | |||||
Das Visuelle Model steuert den Ablauf der aufrufe der Openvibe Funktionen fuer das visuelle BCI | |||||
''' | |||||
from subprocess import * | |||||
from threading import Thread | |||||
import time | |||||
import re | |||||
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(2) | |||||
self.positionWindow("p300") | |||||
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_visuell().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_visuell().split(" ") | |||||
process = Popen(command, stdout=PIPE, universal_newlines=True) | |||||
self.openVibeAktiv = True | |||||
counter = 0 | |||||
acc = 0 | |||||
while True: | |||||
output = process.stdout.readline() | |||||
print(output.strip()) | |||||
x = output.find("aka Classifier trainer") | |||||
accuracy = output.find("Cross-validation test 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 (' + acc + ')\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 | |||||
if(accuracy != -1): | |||||
ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])') | |||||
test = output.encode("windows-1252").decode("utf-8") | |||||
i = len("Cross-validation test") | |||||
acc_s = test[accuracy+i:accuracy+i+41].strip() | |||||
acc = ansi_escape.sub('', acc_s) | |||||
print(acc) | |||||
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(2) | |||||
self.positionWindow("p300") | |||||
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() | |||||
'''-------------------------------------------------------------------------------------------------- | |||||
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 | |||||
print("python2.7") | |||||
except ImportError: #Fuer Python >3 | |||||
from tkinter import * | |||||
from tkinter import filedialog as fd | |||||
print("python >3") | |||||
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) | |||||
img = PhotoImage(file='icon.png') | |||||
self.tk.call('wm', 'iconphoto', self._w, img) | |||||
self.controller = c | |||||
self.PATH_DEFAULT = path_default | |||||
self.title("Visuelles Buchstabieren") | |||||
self.h = self.winfo_screenheight() | |||||
self.w = self.winfo_screenwidth() | |||||
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("<Configure>", 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 | |||||
''' | |||||
try: | |||||
print("closing") | |||||
self.controller.commandStop() | |||||
self.controller.stopAcquisitionServer() | |||||
print("destroy") | |||||
self.dialog.destroy() | |||||
except: | |||||
pass | |||||
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 setDefaultPath(self, path): | |||||
self.PATH_DEFAULT = path | |||||
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() | |||||
self.dialog.title("Visuelles Buchstabieren") | |||||
h = 100 | |||||
w = 400 | |||||
self.dialog.geometry('{}x{}'.format(w,h)) | |||||
self.dialog.geometry("+{}+{}".format(100,200)) | |||||
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=50, 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*9)/10, width= width) | |||||
self.buttonFrame.configure(height=(height)/10, width= width) |
#include <iostream> | |||||
#include <cstring> | |||||
using namespace std; | |||||
extern "C"{ | |||||
//allgemein | |||||
//------------------------------------------------------------------------------------------------------------------------------------- | |||||
string PATH_OV = "meta/dist/Release/openvibe-designer.sh"; | |||||
string PATH_AquisitionServer = "meta/dist/Release/openvibe-acquisition-server.sh"; | |||||
//visuell | |||||
//------------------------------------------------------------------------------------------------------------------------------------- | |||||
string PATH_FILES_Visual = "Projekte/OpenVibe_THN-p300-bci-main/p300-visual/"; | |||||
string pathOVFile_visuell = "Projekte/OpenVibe_THN-p300-bci-main/p300-visual/signals/p300-xdawn-train.ov"; | |||||
string pathClassifierCFG_visuell = "Projekte/OpenVibe_THN-p300-bci-main/p300-visual/cfg/p300-classifier.cfg"; | |||||
string pathSpatialCFG_visuell = "Projekte/OpenVibe_THN-p300-bci-main/p300-visual/cfg/p300-spatial-filter.cfg"; | |||||
string PATH_DEFAULT_visuell = "Projekte/OpenVibe_THN-p300-bci-main/p300-visual/datasets"; | |||||
string fileCopySpellingVisuell = "p300-xdawn-1-acquisition.xml"; | |||||
string filefreeSpellingVisuell = "p300-xdawn-4-online.xml"; | |||||
string fileXDawnTrainingVisuell = "p300-xdawn-2-train-xDAWN.xml"; | |||||
string fileClassifierTrainingVisuell = "p300-xdawn-3-train-classifier.xml"; | |||||
//taktil | |||||
//------------------------------------------------------------------------------------------------------------------------------------ | |||||
string fileCopySpellingTaktil = "p300-tactile-1-acquisition.xml"; | |||||
string filefreeSpellingTaktil = "p300-tactile-4-online.xml"; | |||||
string fileXDawnTrainingTaktil = "p300-tactile-2-train-xDAWN.xml"; | |||||
string fileClassifierTrainingTaktil = "p300-tactile-3-train-classifier.xml"; | |||||
string PATH_FILES_taktil = "Projekte/OpenVibe_THN-p300-bci-main/p300-tactile/"; | |||||
string pathOVFile_taktil = "Projekte/OpenVibe_THN-p300-bci-main/p300-tactile/signals/p300-xdawn-train.ov"; | |||||
string pathClassifierCFG_taktil = "Projekte/OpenVibe_THN-p300-bci-main/p300-tactile/cfg/p300-classifier.cfg"; | |||||
string pathSpatialCFG_taktil = "Projekte/OpenVibe_THN-p300-bci-main/p300-tactile/cfg/p300-spatial-filter.cfg"; | |||||
string PATH_DEFAULT_taktil = "Projekte/OpenVibe_THN-p300-bci-main/p300-tactile/datasets"; | |||||
string PATH_FILES_ConfigFile = "Projekte/OpenVibe_THN-p300-bci-main/cfg/OV_TACTILE_PANDA.conf"; | |||||
//Befehle | |||||
//------------------------------------------------------------------------------------------------------------------------------------- | |||||
string command = "bash"; | |||||
string nogui = "--no-gui"; | |||||
string play = "--play"; | |||||
string playFast = "--play-fast"; | |||||
string config = "--config"; | |||||
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(config).append(" ").append(PATH_FILES_ConfigFile).append(" ").append( play).append(" ").append(PATH_FILES_taktil).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_Visual).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(config).append(" ").append(PATH_FILES_ConfigFile).append(" ").append( play).append(" ").append(PATH_FILES_taktil).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_Visual).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_taktil() | |||||
{ | |||||
string s = ""; | |||||
s = s.append(command).append(" ").append(PATH_OV).append(" ").append(config).append(" ").append(PATH_FILES_ConfigFile).append(" ").append( playFast).append(" ").append(PATH_FILES_taktil).append(fileXDawnTrainingTaktil).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_visuell() | |||||
{ | |||||
string s = ""; | |||||
s = s.append(command).append(" ").append(PATH_OV).append(" ").append( playFast).append(" ").append(PATH_FILES_Visual).append(fileXDawnTrainingVisuell).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_visuell() | |||||
{ | |||||
string s = ""; | |||||
s = s.append(command).append(" ").append(PATH_OV).append(" ").append( playFast).append(" ").append(PATH_FILES_Visual).append(fileClassifierTrainingVisuell).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_taktil() | |||||
{ | |||||
string s = ""; | |||||
s = s.append(command).append(" ").append(PATH_OV).append(" ").append(config).append(" ").append(PATH_FILES_ConfigFile).append(" ").append( playFast).append(" ").append(PATH_FILES_taktil).append(fileClassifierTrainingTaktil).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_visuell() | |||||
{ | |||||
string s = PATH_DEFAULT_visuell; | |||||
char char_array[s.length()+1]; | |||||
strcpy(char_array, s.c_str()); | |||||
char* s_convert = char_array; | |||||
return s_convert; | |||||
} | |||||
char* getDefaultPath_taktil() | |||||
{ | |||||
string s = PATH_DEFAULT_taktil; | |||||
char char_array[s.length()+1]; | |||||
strcpy(char_array, s.c_str()); | |||||
char* s_convert = char_array; | |||||
return s_convert; | |||||
} | |||||
char* getPathOVFile_visuell() | |||||
{ | |||||
string s = pathOVFile_visuell; | |||||
char char_array[s.length()+1]; | |||||
strcpy(char_array, s.c_str()); | |||||
char* s_convert = char_array; | |||||
return s_convert; | |||||
} | |||||
char* getSpatialCFGFile_visuell() | |||||
{ | |||||
string s = pathSpatialCFG_visuell; | |||||
char char_array[s.length()+1]; | |||||
strcpy(char_array, s.c_str()); | |||||
char* s_convert = char_array; | |||||
return s_convert; | |||||
} | |||||
char* getClassifierCFGFile_visuell() | |||||
{ | |||||
string s = pathClassifierCFG_visuell; | |||||
char char_array[s.length()+1]; | |||||
strcpy(char_array, s.c_str()); | |||||
char* s_convert = char_array; | |||||
return s_convert; | |||||
} | |||||
char* getPathOVFile_taktil() | |||||
{ | |||||
string s = pathOVFile_taktil; | |||||
char char_array[s.length()+1]; | |||||
strcpy(char_array, s.c_str()); | |||||
char* s_convert = char_array; | |||||
return s_convert; | |||||
} | |||||
char* getSpatialCFGFile_taktil() | |||||
{ | |||||
string s = pathSpatialCFG_taktil; | |||||
char char_array[s.length()+1]; | |||||
strcpy(char_array, s.c_str()); | |||||
char* s_convert = char_array; | |||||
return s_convert; | |||||
} | |||||
char* getClassifierCFGFile_taktil() | |||||
{ | |||||
string s = pathClassifierCFG_taktil; | |||||
char char_array[s.length()+1]; | |||||
strcpy(char_array, s.c_str()); | |||||
char* s_convert = char_array; | |||||
return s_convert; | |||||
} | |||||
} | |||||
'''-------------------------------------------------------------------------------------------------- | |||||
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() |
# OpenVibe_THN-p300-bci | |||||
Die Szenarien für das Taktile und das Visuelle BCI, basieren auf dem OpenVibeSzenrio p300-speller-xDAWN. | |||||
In die jeweiligen Ordner können die aktuellen OpenVibe-Dateien für das taktile und visuelle Buchstabieren eingefügt werden. Die Dateien können im EFI-Git gefunden werden. |
sudo apt-get install python-tk | |||||
sudo apt-get install xdotool | |||||
sudo apt-get install python-setuptools | |||||
sudo apt-get install python-pip | |||||
pip install pyinstaller==3.6 |
#!/bin/bash | |||||
cd ~/bci/ | |||||
> log.txt | |||||
chmod +rw log.txt | |||||
./gui >> log.txt | |||||