class bciApp(bciCore): def __init__(self): super(bciApp, self).__init__(config_path=r'./config.js') self.PHASES = [{ 'name': 'start', 'next': 'test', 'duration': 1 }, { 'name': 'test', 'next': 'relax', 'duration': 5 }, { 'name': 'relax', 'next': 'test', 'duration': 3 }, { 'name': 'rrelax', 'next': 'stop', 'duration': 1 }] self.CODER = DefaultCoder() layout = { 'screen': { 'size': (1000, 250), 'color': (0, 0, 0), 'type': 'normal', 'Fps': 60, 'caption': 'this is an example' }, 'ssvep1': { 'class': 'sinBlock', 'parm': { 'size': (150, 150), 'position': (125, 125), 'bordercolor': (0, 0, 0), 'anchor': 'center', 'frequency': 6, 'visible': True, 'start': False } }, 'ssvep2': { 'class': 'sinBlock', 'parm': { 'size': (150, 150), 'position': (375, 125), 'bordercolor': (0, 0, 0), 'anchor': 'center', 'frequency': 7, 'visible': True, 'start': False } }, 'ssvep3': { 'class': 'sinBlock', 'parm': { 'size': (150, 150), 'position': (625, 125), 'bordercolor': (0, 0, 0), 'anchor': 'center', 'frequency': 8, 'visible': True, 'start': False } }, 'ssvep4': { 'class': 'sinBlock', 'parm': { 'size': (150, 150), 'position': (875, 125), 'bordercolor': (0, 0, 0), 'anchor': 'center', 'frequency': 9, 'visible': True, 'start': False } }, } self.gui = GuiIF(None, layout) _ = multiprocessing.Process(target=guiengine_proc, args=(self.gui.args, )) _.start() self.gui.wait() sp_ip = self.configs['signal_processing']['sp_host_ip'] sp_port = self.configs['signal_processing']['sp_host_port'] self.marker = Marker((sp_ip, sp_port)) self.TEST_NUM = 80 self.test_count = 1 def transition(self, phase): write_log(phase) if phase == 'test': self.gui.update( { 'ssvep1': { 'start': True, 'bordercolor': (0, 0, 0) }, 'ssvep2': { 'start': True, 'bordercolor': (0, 0, 0) }, 'ssvep3': { 'start': True, 'bordercolor': (0, 0, 0) }, 'ssvep4': { 'start': True, 'bordercolor': (0, 0, 0) } }, {}) t = global_clock() print(t) self.marker.send_marker( {'process': { 'value': [1], 'timestamp': [t] }}) #开始测试 elif phase == 'relax': self.gui.update( { 'ssvep1': { 'start': False }, 'ssvep2': { 'start': False }, 'ssvep3': { 'start': False }, 'ssvep4': { 'start': False } }, {}) self.marker.send_marker( {'process': { 'value': [2], 'timestamp': [global_clock()] }}) #测试完成 self.test_count += 1 if self.test_count > self.TEST_NUM: self.change_phase('rrelax') def stop_run(self): self.gui.quit() def process(self, result): if result is not None: print(result) mapp = {'6': 'ssvep1', '7': 'ssvep2', '8': 'ssvep3', '9': 'ssvep4'} self.gui.update({mapp[str(result)]: { 'bordercolor': (255, 0, 0) }}, {})
class GuiEngine(): stimuli = {} __release_ID_list = [] def __init__(self, stims, Q_c2g, E_g2c, server_address): """ stims: dict to define a stimulus. eg. stims = {'cue':{'class':'Block','parm':{'size':(100,40),'position':(0,0)}}} Q_c2g: multiprocessing.Queue, used for accepting stimulus control command from core process kwargs: server_address = ?, the target server's address to accept marker property for describe screen size: (width,height) type: fullscreen/normal frameless: True/False color: (R,G,B) caption: string Fps: int, strongly suggest you set Fps as the same with system's Fps """ self.Q_c2g = Q_c2g self.E_g2c = E_g2c self.marker_on = False self.marker_event = {} self.stp = False self.lock = threading.Lock() pygame.init() #初始化screen # 当且仅当window环境变量设置成功且fullscreen时,SCREEN_SYNC=True if stims['screen']['type'].lower() == 'fullscreen': self.screen = pygame.display.set_mode( (0, 0), FULLSCREEN | DOUBLEBUF | HWSURFACE, 32) else: # 将窗口置中 if OS == 'windows': w, h = stims['screen']['size'] x = int((SCRW - w) / 2.) y = int((SCRH - 50 - h) / 2.) - 50 # 扣除任务栏高度 os.environ['SDL_VIDEO_WINDOW_POS'] = '%i,%i' % (x, y) self.screen = pygame.display.set_mode(stims['screen']['size'], NOFRAME | DOUBLEBUF, 32) SCREEN_SYNC = False self.screen_color = stims['screen']['color'] self.screen.fill(self.screen_color) pygame.display.set_caption(stims['screen']['caption']) self.Fps = stims['screen']['Fps'] del stims['screen'] self.ask_4_update_gui = False #线程接收到刷新请求后,通知主进程刷新 self.update_in_this_frame = False #主进程在一帧真实的刷新帧中确定能够进行刷新 self.__update_per_frame_list = [] #接受帧刷新对象 if server_address is None: class Marker(): def __init__(self, sa): pass def send_marker(self, marker): raise Exception( 'marker_sender was not initilized because server_address parameter was not given' ) self.marker_sender = Marker(server_address) #注册刺激,生成实例 for ID in stims: element = stims[ID] clas = element['class'] if clas in MODULES: self.stimuli[ID] = MODULES[clas](self.screen, **element['parm']) backthread = threading.Thread(target=self.backthreadfun, args=(), daemon=True) backthread.start() def backthreadfun(self): #接收刷新请求字典 # arg = self.Q_c2g.get() # arg可能的形式: # 1. 单字符串:'_q_u_i_t_' -> 结束标志 # 2. 列表:[stimulus setting, marker] -> 刺激设置,marker标志 # 3. marker: eg. {'mkr1':{'value':[0]}} while True: arg = self.Q_c2g.get() if arg == '_q_u_i_t_': self.stp = True #用于终止主程序 break stimulus_arg, self.marker_event = arg #marker is a dict self.lock.acquire() [ self.stimuli[id].reset(**stimulus_arg[id]) for id in stimulus_arg ] #更新刺激实例的参数 self.ask_4_update_gui = True #请求刷新 self.lock.release() print('[guiengine] sub thread ended') def StartRun(self): print('[guiengine] process started') self.E_g2c.set() clock = pygame.time.Clock() # END = 0 while True: self.screen.fill(self.screen_color) if self.ask_4_update_gui: #子线程请求刷新 self.update_in_this_frame = True #将在这一帧刷新 self.ask_4_update_gui = False #.items()方法将stimuli字典转换为列表,元素为元祖,k[0]对应ID, k[1]为具体的刺激对象实例 # 意思是按照layer属性排序 stis = sorted(self.stimuli.items(), key=lambda k: k[1].layer) [s[1].show() for s in stis] #按照图层书序顺序绘图,layer越大,越顶层 pygame.display.flip() #该帧刷新完毕 if not SCREEN_SYNC: clock.tick(self.Fps) # 有刷新请求,且在该帧完成了刷新 if self.update_in_this_frame: _clk = global_clock() if len(self.marker_event) > 0: #确实接受到了marker for ky in self.marker_event: # 将时间戳记录下来 self.marker_event[ky]['timestamp'] = _clk self.marker_sender.send_marker(self.marker_event) self.update_in_this_frame = False pygame.event.get() if self.stp: break #只能通过主控结束 pygame.quit() [self.stimuli[id].release() for id in self.stimuli] #更新刺激实例的参数 print('[guiengine] process exit')
class bciApp(bciCore): def __init__(self): super(bciApp,self).__init__(config_path = r'./config.js') self.PHASES = [ {'name':'start','next':'test','duration':1}, {'name':'test','next':'relax','duration':7}, {'name':'relax','next':'test','duration':5}, {'name':'rrelax','next':'stop','duration':1}] self.CODER = DefaultCoder() w = win32api.GetSystemMetrics(win32con.SM_CXSCREEN) h = win32api.GetSystemMetrics(win32con.SM_CYSCREEN) camera_h = 2*240 camera_w = 2*320 layout = {'screen': {'size': (w, h), 'color': (0, 0, 0), 'type': 'normal', 'Fps': 60, 'caption': 'this is an example'}, 'camera':{'class':'MjpegStream','parm':{'size':(camera_w,camera_h),'position':(int(w/2),int(h/2)), 'anchor':'center','visible':True,'start':True,'url':'http://192.168.1.1:8080/?action=stream'}}, 'ssvep1': {'class': 'sinCircle', 'parm': {'radius':65, 'position': (int(0.5*w-320-65), int(0.5*h-240+30)), 'text':'forward','textsize':20,'frequency': 6.6, 'visible': True, 'start': False}}, 'ssvep2': {'class': 'sinCircle', 'parm': {'radius':65, 'position': (int(0.5*w-320-65), int(0.5*h)), 'text':'left','textsize':20,'frequency': 7.6, 'visible': True, 'start': False}}, 'ssvep3': {'class': 'sinCircle', 'parm': {'radius':65, 'position': (int(0.5*w-320-65), int(0.5*h+240-30)), 'text':'r-left','textsize':20,'frequency': 8.6, 'visible': True, 'start': False}}, 'ssvep4': {'class': 'sinCircle', 'parm': {'radius':65, 'position': (int(0.5*w+320+65), int(0.5*h-240+30)), 'text':'backward','textsize':20,'frequency': 9.3, 'visible': True, 'start': False}}, 'ssvep5': {'class': 'sinCircle', 'parm': {'radius':65, 'position': (int(0.5*w+320+65), int(0.5*h)), 'text':'right','textsize':20,'frequency': 12.2, 'visible': True, 'start': False}}, 'ssvep6': {'class': 'sinCircle', 'parm': {'radius':65, 'position': (int(0.5*w+320+65), int(0.5*h+240-30)), 'text':'r-right','textsize':20,'frequency': 13.8, 'visible': True, 'start': False}}, } self.gui = GuiIF(None,layout) _ = multiprocessing.Process(target=guiengine_proc,args=(self.gui.args,)) _.start() self.gui.wait() sp_ip = self.configs['signal_processing']['sp_host_ip'] sp_port = self.configs['signal_processing']['sp_host_port'] self.marker = Marker((sp_ip,sp_port)) self.TEST_NUM = 12 self.test_count = 1 self.ROBOT = WIFIROBOT_CTR() def transition(self,phase): write_log(phase) if phase == 'test': self.gui.update({'ssvep1': {'start': True,'bordercolor':(0,0,0)}, 'ssvep2': {'start': True,'bordercolor':(0,0,0)}, 'ssvep3': {'start': True,'bordercolor':(0,0,0)}, 'ssvep4': {'start': True,'bordercolor':(0,0,0)},'ssvep5': {'start': True,'bordercolor':(0,0,0)},'ssvep6': {'start': True,'bordercolor':(0,0,0)}}, {}) t = global_clock() self.marker.send_marker({'process':{'value':[1],'timestamp':[t]}}) #开始测试 elif phase == 'relax': self.gui.update({'ssvep1': {'start': False,'bordercolor':(0,0,0)}, 'ssvep2': {'start': False,'bordercolor':(0,0,0)}, 'ssvep3': {'start': False,'bordercolor':(0,0,0)}, 'ssvep4': {'start': False,'bordercolor':(0,0,0)},'ssvep5': {'start': False,'bordercolor':(0,0,0)},'ssvep6': {'start': False,'bordercolor':(0,0,0)}}, {}) self.marker.send_marker({'process': {'value': [2],'timestamp':[global_clock()]}}) #测试完成 self.test_count += 1 if self.test_count > self.TEST_NUM: self.change_phase('rrelax') def stop_run(self): self.marker.send_marker({'endsigpro': {'value':[1],'timestamp':[global_clock()]}}) #测试完成 self.gui.quit() self.ROBOT.close() def process(self,result): if result is not None: print(result) self.gui.update({'ssvep%s'%(result+1): {'bordercolor':(255,0,0)}},{}) self.ROBOT.go(cmdss[result][0],cmdss[result][1])