def dump_data_to_file_cap_by_size(self, ): if not self.raw_eye_task_data_limit_reached(): return tempCache = globls.raw_eye_task_data # Clean up all the global data variables globls.update_raw_eye_task_data([]) # Dump configuration data, actual data from eyelink or 3rd party server config = [] config.append(len(tempCache)) config.append(globls.offset_gain_config['left_offset_x']) config.append(globls.offset_gain_config['left_gain_x']) config.append(globls.offset_gain_config['left_offset_y']) config.append(globls.offset_gain_config['left_gain_y']) config.append(globls.offset_gain_config['right_offset_x']) config.append(globls.offset_gain_config['right_gain_x']) config.append(globls.offset_gain_config['right_offset_y']) config.append(globls.offset_gain_config['right_gain_y']) # Note: if there is loss of data then, it is better to deep copy raw_eye_task_data # into a temp file, update the globls.update_raw_eye_task_data([]) with # empty list # Then call the write_data() to write into file. # Update total_records based on temp file # Ensure to remove the last line in this method. self.write_data(config, tempCache) # Keep track of total data written self.total_records += len(tempCache)
def process_eye_capture_method_selection_callback(self): ''' Process the options for recording :return: ''' if int(self.eye_recording_method.get()) == 1: # # Keep the child window selected # self.eye_recording_win.lift(aboveThis=self.parent) for i in range(EyeCoilChannelId.C16 + 1): self.eye_coil_channel_obj[i].configure(state=tk.NORMAL) if len(self.get_channel_selected_list()) >= 6: for i in range(EyeXYZIndex.TWAIN_XYZ_INDEX): self.eye_pos_option_menu_object[i].configure(state=tk.NORMAL) recording_method_name = 'Eye Coil' elif int(self.eye_recording_method.get()) == 0: for i in range(EyeCoilChannelId.C16 + 1): self.eye_coil_channel_obj[i].configure(state=tk.DISABLED) for i in range(EyeXYZIndex.TWAIN_XYZ_INDEX): self.eye_pos_option_menu_object[i].configure(state=tk.DISABLED) recording_method_name = 'Eye Link' else: # No eye tracking recording_method_name = 'No Eyes' globls.update_eye_recording_method_parameters(int(self.eye_recording_method.get()), recording_method_name)
def dump_data_to_file(self): ''' Dump data to file :return: ''' # Set the flag not to collect data self.update_data_collect_flag(False) tempCache = globls.raw_eye_task_data globls.update_raw_eye_task_data([]) # Dump configuration data, actual data from eyelink or 3rd party server config = [] config.append(len(tempCache)) config.append(globls.offset_gain_config['left_offset_x']) config.append(globls.offset_gain_config['left_gain_x']) config.append(globls.offset_gain_config['left_offset_y']) config.append(globls.offset_gain_config['left_gain_y']) config.append(globls.offset_gain_config['right_offset_x']) config.append(globls.offset_gain_config['right_gain_x']) config.append(globls.offset_gain_config['right_offset_y']) config.append(globls.offset_gain_config['right_gain_y']) self.write_data(config, tempCache) #Keep track of total data written self.total_records += len(tempCache)
def save_raw_eye_taskdata(self, ts, left_eye_x=0, left_eye_y=0, right_eye_x=0, right_eye_y=0, task_data=None): ''' Save eye data to a list to be later writted to a file :param ts: :param left_eye_x: :param left_eye_y: :param right_eye_x: :param right_eye_y: :param pupil_size_left: :param pupil_size_right: :return: ''' if self.data_collect_flag: # Save timestamp, leftx, lefty, pupilzise, rightx, righty, pupil size, task data # task data is Null as there is no task data when eye data is collected data = [ ts, left_eye_x, left_eye_y, right_eye_x, right_eye_y, '' if task_data is None else task_data ] globls.update_raw_eye_task_data(data)
def update_getmean_eye_sample(self, left_eye_x, left_eye_y, right_eye_x, right_eye_y, eye_closed): ''' Update the eye sample to get the mean :param left_eye_x: :param left_eye_y: :param right_eye_x: :param right_eye_y: :param eye_closed: :return: ''' if eye_closed: return [0, 0, 0, 0] # update the raw eye sample to global variable globls.update_raw_eye_data_sample(left_eye_x, left_eye_y, right_eye_x, right_eye_y, remove=True, append=True) # calculate the mean and return the mean value eye_data_array = np.array(globls.raw_eye_data_sample) left_mean = np.mean(eye_data_array[const.LEFT], axis=0).tolist() right_mean = np.mean(eye_data_array[const.RIGHT], axis=0).tolist() # return left (x, y) mean right (x, y) mean return left_mean[0], left_mean[1], right_mean[0], right_mean[1]
def __init__(self): root = tk.Tk() globls.update_gui_parameters(root=root) # Main thread which is the GUI thread gui = Gui() globls.update_gui_parameters(gui_object=gui) # Set up thread # Set up the thread to do asynchronous socket # More can be made if necessary self.stop_threads = threading.Event() self.stop_threads.clear() if globls.eye_recording_method != EyeRecordingMethods.EYE_NONE: # Eye interpreter self.eye_interpreter_thread = threading.Thread(target=EyeInterpret) self.eye_interpreter_thread.setDaemon(True) self.eye_interpreter_thread.start() self.arbitrator_server_thread = threading.Thread( target=ArbitratorServer) self.arbitrator_server_thread.setDaemon(True) self.arbitrator_server_thread.start() self.exit_check_periodic_call() root.mainloop()
def __init__(self): # self.DIO_obj = DIO() # for programing printer port sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # sock.bind(('', globls.config_param['arbitrator_service']['local_port'])) sock.bind(('100.1.1.3', globls.config_param['arbitrator_service']['local_port'])) sock_eye = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # sock_eye.bind(('', globls.config_param['arbitrator_service']['local_port_eye'])) sock_eye.bind( ('100.1.1.3', globls.config_param['arbitrator_service']['local_port_eye'])) # sock.settimeout(30) globls.update_arbitrator_server_socket(sock, sock_eye) self.eye_check = ValidateVergenceVersion() # send the UDP packet to initiate the connection data = '{} {}/'.format(Constant.COMMAND_WORD_CONNECTION, Constant.CONNECTION_START) util.send_data(globls.arbitrator_sock, globls.arbitrator_sock_addr, data, 'Connection Initiation Message') self.receiver()
def eye_in_out(self): ''' validate the version data Eye in or out of the specific window ''' left_eye_x = globls.eye_data[const.LEFT][const.X] left_eye_y = globls.eye_data[const.LEFT][const.Y] right_eye_x = globls.eye_data[const.RIGHT][const.X] right_eye_y = globls.eye_data[const.RIGHT][const.Y] left_eye_in_out = 0 right_eye_in_out = 0 # Different set of points points_list = globls.centre_of_windows # Loop through all the target points specified to see where the eye is for i in range(len(points_list)): left_eye_in_out = 0 right_eye_in_out = 0 left_tp_x, left_tp_y, right_tp_x, right_tp_y = \ util.get_disparity_offset_applied_points(points_list[i][0], points_list[i][1], points_list[i][2]) diameter_in_mm, tmp = util.convert_deg_to_mm(points_list[i][3]) # Has left and right eye selected left side of the choice # TP: x, y, Diameter left_eye_in = self._is_eye_in(left_eye_x, left_eye_y, left_tp_x, left_tp_y, diameter_in_mm / 2) right_eye_in = self._is_eye_in(right_eye_x, right_eye_y, right_tp_x, right_tp_y, diameter_in_mm / 2) if left_eye_in: left_eye_in_out = i + 1 if right_eye_in: right_eye_in_out = i + 1 if left_eye_in_out and right_eye_in_out: break # If UI has any specific Eye selected left, right = globls.eye_selected['left'], globls.eye_selected['right'] # If only left or only right eye is selected on UI then # set the other eye to be in if left and not right: right_eye_in_out = left_eye_in_out elif right and not left: left_eye_in_out = right_eye_in_out elif not right and not left: left_eye_in_out = right_eye_in_out = 0 globls.update_eye_in_out(left_eye_in_out, right_eye_in_out)
def button_1_callback(self): '''Write your function here if it's simple. If it is more complex, you might want to import it from a separate document and call it here.''' if not DataFileObj.data_collect_flag: if not DataFileObj.is_data_file_created(): # Create the file DataFileObj.update_file_name(globls.subject_name) DataFileObj.update_header_into_data_file() globls.dump_log('start saving data') globls.custom_button[0].configure(text="Stop Save") globls.update_cont_data(1) DataFileObj.update_data_collect_flag(True) # print(globls.DUMP_DATA_CONTINUALLY) else: globls.dump_log('stop saving data') globls.DUMP_DATA_CONTINUALLY = 0 DataFileObj.update_data_collect_flag(False) globls.update_cont_data(0) globls.custom_button[0].configure(text="Start Save") # DataFileObj.dump_data_to_file() # DataFileObj.total_data_dumped_to_file() DataFileObj.reset_file_name() return
def button_2_callback(self): globls.dump_log('Gate is opened') data_str = '6 100 /' data_recv_ts = time.time() data = data_str + """{}""".format('q' * (1024 - len(data_str.encode()))) DataFileObj.save_raw_eye_taskdata(data_recv_ts, 0, 0, 0, 0, task_data=data) return
def save_eye_reording_information(self): ''' Save the selected information :return: ''' # Store the channels used for x, y and z if int(self.eye_recording_method.get()) == 1: eye_pos = self.get_eye_positions_channel() # store the channels list channel_list_selected = [] for i in range(EyeCoilChannelId.C16 + 1): if self.eye_coil_channel[i].get(): channel_list_selected.append(i) eye_coil_channels = util.convert_bit_to_int(channel_list_selected) globls.update_eye_recording_method_parameters(eye_coil_channels=eye_coil_channels, eye_pos=eye_pos) self.eye_recording_win.destroy()
def __init__(self): root = tk.Tk() globls.update_gui_parameters(root=root) # Main thread which is the GUI thread gui = Gui() globls.update_gui_parameters(gui_object=gui) # Setup thread # Set up the thread to do asynchronous socket # More can be made if necessary self.stop_threads = threading.Event() self.stop_threads.clear() # # Eye interpreter self.eye_interpreter_thread = threading.Thread(target=EyeInterpret) self.eye_interpreter_thread.setDaemon(True) self.eye_interpreter_thread.start() self.arbitrator_server_thread = threading.Thread( target=ArbitratorServer) self.arbitrator_server_thread.setDaemon(True) self.arbitrator_server_thread.start() self.exit_check_periodic_call() # Check if Ripple Grapevine is connected if messagebox.askyesno("Connect to Ripple?", "Do you want to connect to Ripple?", parent=root): try: xpConnection = xp.xipppy_open(use_tcp=True) xpConnection.__enter__() globls.XIPPPY_CONNECTION = True print('Connection to Ripple Grapevine established.') # Test connection by printing time print('Printing time stamp: ', xp.time()) except Exception as e: print('Ripple Grapevine is not connected...') globls.XIPPPY_CONNECTION = False else: print('User declined to connect to Ripple.') globls.XIPPPY_CONNECTION = False root.mainloop()
def send_data(sock, dest_addr, data_string, msg=None): data = data_string tmp_msg = '' if dest_addr: data = data_padder(data_string) try: sock.sendto(data, dest_addr) if msg is not None: tmp_msg = tmp_msg + msg globls.dump_log('{}. length {}. Data {}'.format( tmp_msg, len(data), data_string)) return data except Exception as e: log.exception(e) tmp_msg = 'Exception Sending ' + msg if msg else '' else: tmp_msg = 'Matlab socket not initilized to Send ' + msg if msg else '' globls.dump_log('Error: {}'.format(tmp_msg)) return data
def total_data_dumped_to_file(self): globls.dump_log('Total data written to file is {}'.format( self.total_records))
def receiver(self): ''' Receiver loop to check the incoming packets :return: ''' # globls.dump_log("Running Matlab thread") globls.dump_log('Listening to 3rd party messages') while globls.is_program_running: try: bin_data, addr = globls.arbitrator_sock.recvfrom( globls.constant['data_size_length']) data = bin_data.decode() data_recv_ts = time.time() # process the variables if len(data): # Check if there is any delimiter in the message '/' if yes then split cmd_lists = data.split( globls.constant['message_delimiter']) # Data before / is valid data read and remove the space cmd_list = cmd_lists[0].split() if int(cmd_list[0]) == Constant.COMMAND_WORD_CONNECTION: if int(cmd_list[1]) == Constant.CONNECTION_START: # send the UDP packet to initiate the connection data = '{} {}/{} {}/{} {}/{} {}/{} {}/'.format( Constant.COMMAND_WORD_CONNECTION, Constant.CONNECTION_ACK, const.SCREEN_HEIGHT, globls.arbitrator_display['screen_height_mm'], const.SCREEN_DISTANCE, globls. arbitrator_display['screen_distance_mm'], const.SCREEN_WIDTH, globls.arbitrator_display['screen_width_mm'], const.SCREEN_IOD, globls.arbitrator_display['iod_mm']) util.send_data(globls.arbitrator_sock, globls.arbitrator_sock_addr, data, 'Connection Ack Message') globls.update_load_subject_task_config_flag(True) elif int(cmd_list[1]) == Constant.CONNECTION_ACK: globls.connection_state = Constant.CONNECTION_ACK # Update this flag to ensure that the user knows what is the next step after connection is up globls.update_load_subject_task_config_flag(True) # util.send_screen_parameters() # print cmd_list elif int(cmd_list[0]) == Constant.DISPLAY_COMMAND_WORD: config = [int(cmd_list[1]), cmd_list[2]] # print(config) globls.update_displayable_config(config) # Process the exit call elif (int(cmd_list[0]) == Constant.COMMAND_WORD_CONTROL and int(cmd_list[1]) == Constant.CONTROL_EXIT): print('breaking code (arbitrator_server: line 99)') break elif int(cmd_list[0]) == Constant.EYE_IN_OUT_REQUEST: eye_in_out = copy.copy(globls.eye_in_or_out) # if (eye_in_out[0] != globls.last_sent_eye_in_out[0] # or eye_in_out[1] != globls.last_sent_eye_in_out[1]): # '{LEye_Status} {in/out} # {LEye_X_gain} {LEye_X_offset} # {LEye_Y_gain} {LEye_Y_offset}/... # {REye_Status} {in/out} # {REye_X_gain} {REye_X_offset} # {REye_Y_gain} {REye_Y_offset}/' data = '{} {} {} {} {} {}/{} {} {} {} {} {}/'.format( Constant.LEFT_EYE_STATUS, globls.eye_in_or_out[0], globls.offset_gain_config[ ConfigLabels.LEFT_EYE_GAIN_X], globls.offset_gain_config[ ConfigLabels.LEFT_EYE_OFFSET_X], globls.offset_gain_config[ ConfigLabels.LEFT_EYE_GAIN_Y], globls.offset_gain_config[ ConfigLabels.LEFT_EYE_OFFSET_Y], Constant.RIGHT_EYE_STATUS, globls.eye_in_or_out[1], globls.offset_gain_config[ ConfigLabels.RIGHT_EYE_GAIN_X], globls.offset_gain_config[ ConfigLabels.RIGHT_EYE_OFFSET_X], globls.offset_gain_config[ ConfigLabels.RIGHT_EYE_GAIN_Y], globls.offset_gain_config[ ConfigLabels.RIGHT_EYE_OFFSET_Y], ) # if (eye_in_out[0] != globls.last_sent_eye_in_out[0] # or eye_in_out[1] != globls.last_sent_eye_in_out[1]): # data = '{} {}/{} {}/'.format(Constant.LEFT_EYE_STATUS, globls.eye_in_or_out[0], # Constant.RIGHT_EYE_STATUS, globls.eye_in_or_out[1]) util.send_data(globls.arbitrator_sock_eye, globls.arbitrator_sock_addr_eye, data) # print "EYE in or out ", data globls.update_last_sent_eye_in_out(eye_in_out) elif int(cmd_list[0] ) == Constant.LATCHED_EYE_IN_OUT_REQUEST: globls.latched_eye = 1 globls.caught = 0 # if just starting latched eye request, couldn't have caught eye out! globls.dump_log('Initiating latched eye request') elif int(cmd_list[0]) == Constant.END_LATCHED_EYE: globls.latched_eye = 0 globls.caught = 0 # matlab finally caught your message about version violation globls.dump_log('Ending latched eye request') elif int(cmd_list[0]) == Constant.VERGENCE_REQUEST: points = list(map(float, cmd_list[1:6])) value = self.eye_check.vergence_error(points) # if value != globls.last_vergence_error_sent: data = '{} {}/'.format(Constant.VERGENCE_STATUS, value) util.send_data(globls.arbitrator_sock_eye, globls.arbitrator_sock_addr_eye, data) # print "Vergence error ", data globls.update_last_sent_vergence_error(value) elif int(cmd_list[0]) == Constant.SCREEN_WINDOW_WIDTH: globls.update_arbitrator_server_screen_resolution( width=int(cmd_list[1])) globls.dump_log( 'Received the screen width and scale factor to display on GUI: {}' .format( globls.arbitrator_display['x_scale_factor'])) elif int(cmd_list[0]) == Constant.SCREEN_WINDOW_HEIGHT: globls.update_arbitrator_server_screen_resolution( height=int(cmd_list[1])) globls.dump_log( 'Received the screen Height and scale factor to display on GUI: {}' .format( globls.arbitrator_display['y_scale_factor'])) elif int(cmd_list[0]) == Constant.CENTRE_OF_WINDOWS: # print cmd_list # 100 number list of X Y Z diameter # Maximum 30 points no_of_points = int(cmd_list[1]) config = [] lst = cmd_list[2:] # pair the data and give it to UI for updation for i in range(0, len(lst), 6): config.append([ float(lst[i]), float(lst[i + 1]), float(lst[i + 2]), float(lst[i + 3]), lst[i + 4], lst[i + 5] ]) if len(config ) == Constant.MAXIMUM_CENTRE_OF_WINDOW: break globls.dump_log('Points to draw {}'.format(cmd_list)) globls.update_centre_point(no_of_points, config) elif int(cmd_list[0]) == Constant.WINDOW_ON: # print cmd_list globls.update_centre_window_on_off(True) globls.dump_log('Window On') elif int(cmd_list[0]) == Constant.WINDOW_OFF: # print cmd_list globls.update_centre_window_on_off(False) globls.dump_log('Window Off') # Reset this to -1, -1 so that next time this is queried from # Arbitrator server new values are sent globls.update_last_sent_eye_in_out([-1, -1]) elif int(cmd_list[0]) == Constant.REWARD_ON: # print cmd_list self.DIO_obj.write_digital_bit(1) #self.DIO_obj.reward_on() globls.dump_log('Reward On') elif int(cmd_list[0]) == Constant.REWARD_OFF: # print cmd_list self.DIO_obj.write_digital_bit(0) #self.DIO_obj.reward_off() globls.dump_log('Reward Off') elif int(cmd_list[0]) == Constant.VERGENCE_ON: # print cmd_list globls.udpdate_vergence_display(True) globls.dump_log('Vergence On') elif int(cmd_list[0]) == Constant.VERGENCE_OFF: # print cmd_list globls.udpdate_vergence_display(False) globls.dump_log('Vergence Off') # Reset this to -1 so that next time this is queried from # Arbitrator server new values are sent globls.update_last_sent_vergence_error(-1) elif int(cmd_list[0]) == Constant.DRAW_EVENTS: tempnum = len(cmd_lists) - 1 globls.update_drawing_object_on(1) globls.update_drawing_object_number(tempnum) for i in range(0, tempnum): templist = cmd_lists[i].split() if i == 0: tempx = float(templist[2]) tempy = float(templist[3]) if tempx == -1 and tempy == -1: if not globls.Shocked: globls.shock_on() data_str = '6 201 /' temp_data = data_str + """{}""".format( 'q' * (1024 - len(data_str.encode()))) DataFileObj.save_raw_eye_taskdata( data_recv_ts, 0, 0, 0, 0, task_data=temp_data) globls.update_shock_flag(1) else: # globls.prt.setData(0) if not globls.ManualShock: if globls.Shocked: globls.shock_off() data_str = '6 200 /' temp_data = data_str + """{}""".format( 'q' * (1024 - len(data_str.encode()))) globls.update_shock_flag(0) DataFileObj.save_raw_eye_taskdata( data_recv_ts, 0, 0, 0, 0, task_data=temp_data) else: tempx = float(templist[1]) tempy = float(templist[2]) globls.update_drawing_object_pos(i, 0, tempx) globls.update_drawing_object_pos(i, 1, tempy) elif int(cmd_list[0]) == Constant.EVENTS: globls.dump_log('event {}'.format(cmd_list)) if not globls.DUMP_DATA_CONTINUALLY: if int(cmd_list[1]) == Constant.EVENT_START: # Start the data save DataFileObj.update_data_collect_flag(True) # Dump auto offset data globls.auto_offset_dump_data = 1 # Make sure primer and flag is still off globls.auto_offset_update_primer = 0 globls.auto_offset_update_flag = 0 elif int(cmd_list[1]) == Constant.EVENT_STOP: # This needs to be saved here as we dump the saved data to file # And data collection falg will be reset DataFileObj.save_raw_eye_taskdata( data_recv_ts, globls.last_raw_eye_data[0], globls.last_raw_eye_data[1], globls.last_raw_eye_data[2], globls.last_raw_eye_data[3], task_data=data) # Stop saving the data and dump tp file # Flag to stop saving the data is set inside this function DataFileObj.dump_data_to_file() globls.update_last_sent_vergence_error(-1) globls.update_last_sent_eye_in_out([-1, -1]) # Dump auto offset data globls.auto_offset_dump_data = 1 # Set update flag so offsets can now be changed globls.auto_offset_update_flag = 1 # Check for fixation acquired and hold time acquired to start/stop auto eye offset elif int( cmd_list[1]) == Constant.FIXATION_ACQUIRED: # Set "stop data collection" flag to false globls.auto_offset_stop_collect = 0 # Set "start data collection" flag to true globls.auto_offset_start_collect = 1 # Make sure primer is still off globls.auto_offset_update_primer = 0 elif int(cmd_list[1] ) == Constant.FIXATION_HOLD_COMPLETE: # Set "start data collection" flag to false globls.auto_offset_start_collect = 0 # Set "stop data collection" flag to true globls.auto_offset_stop_collect = 1 elif int(cmd_list[1] ) == Constant.SACCADE_TARGET_ACQUIRED: # Set primer flag to update offsets after this trial is over globls.auto_offset_update_primer = 1 # Save the data from 3rd party server DataFileObj.save_raw_eye_taskdata( data_recv_ts, globls.last_raw_eye_data[0], globls.last_raw_eye_data[1], globls.last_raw_eye_data[2], globls.last_raw_eye_data[3], task_data=data) # # Save the data from 3rd party server # if globls.DUMP_DATA_CONTINUALLY: # DataFileObj.dump_data_continually(data_recv_ts, data) # except socket.timeout: # pass except Exception as e: log.exception(e) globls.arbitrator_sock.close() print('globls.arbitrator_sock was closed (arbitrator_serve: line 290)')
def button_4_callback(self): globls.dump_log( 'Add a custom button function in button_funs.py for the correct button callback!' ) return
def button_3_callback(self): if globls.Shocked: globls.update_shock_flag(0) globls.ManualShock = 0 globls.shock_off() globls.custom_button[2].configure(text="Shock Off") globls.dump_log('Shock Stopped') data_str = '6 200 /' data_recv_ts = time.time() data = data_str + """{}""".format('q' * (1024 - len(data_str.encode()))) DataFileObj.save_raw_eye_taskdata(data_recv_ts, 0, 0, 0, 0, task_data=data) else: globls.update_shock_flag(1) globls.ManualShock = 1 globls.shock_on() globls.custom_button[2].configure(text="Shock On") globls.dump_log('Shock Started') data_str = '6 201 /' data_recv_ts = time.time() data = data_str + """{}""".format('q' * (1024 - len(data_str.encode()))) DataFileObj.save_raw_eye_taskdata(data_recv_ts, 0, 0, 0, 0, task_data=data) return
def receiver(self): ''' Receiver loop to check the incoming packets :return: ''' # globls.dump_log("Running Matlab thread") globls.dump_log('Listening to 3rd party messages') while globls.is_program_running: try: data, addr = globls.arbitrator_sock.recvfrom(globls.constant['data_size_length']) data_recv_ts = time.time() # process the variables if len(data): # Check if there is any delimiter in the message '/' if yes then split cmd_lists = data.split(globls.constant['message_delimiter']) # Data before / is valid data read and remove the space cmd_list = cmd_lists[0].split() if int(cmd_list[0]) == Constant.COMMAND_WORD_CONNECTION: if int(cmd_list[1]) == Constant.CONNECTION_START: # send the UDP packet to initiate the connection data = '{} {}/{} {}/{} {}/{} {}/{} {}/'.format(Constant.COMMAND_WORD_CONNECTION, Constant.CONNECTION_ACK, const.SCREEN_HEIGHT, globls.arbitrator_display[ 'screen_height_mm'], const.SCREEN_DISTANCE, globls.arbitrator_display[ 'screen_distance_mm'], const.SCREEN_WIDTH, globls.arbitrator_display['screen_width_mm'], const.SCREEN_IOD, globls.arbitrator_display['iod_mm']) util.send_data(globls.arbitrator_sock, globls.arbitrator_sock_addr, data, 'Connection Ack Message') globls.update_load_subject_task_config_flag(True) elif int(cmd_list[1]) == Constant.CONNECTION_ACK: globls.connection_state = Constant.CONNECTION_ACK # Update this flag to ensure that the user knows what is the next step after connection is up globls.update_load_subject_task_config_flag(True) # util.send_screen_parameters() # print cmd_list elif int(cmd_list[0]) == Constant.DISPLAY_COMMAND_WORD: config = [int(cmd_list[1]), cmd_list[2]] globls.update_displayable_config(config) # Process the exit call elif (int(cmd_list[0]) == Constant.COMMAND_WORD_CONTROL and int(cmd_list[1]) == Constant.CONTROL_EXIT): break elif int(cmd_list[0]) == Constant.EYE_IN_OUT_REQUEST: eye_in_out = copy.copy(globls.eye_in_or_out) # if (eye_in_out[0] != globls.last_sent_eye_in_out[0] # or eye_in_out[1] != globls.last_sent_eye_in_out[1]): data = '{} {}/{} {}/'.format(Constant.LEFT_EYE_STATUS, globls.eye_in_or_out[0], Constant.RIGHT_EYE_STATUS, globls.eye_in_or_out[1]) util.send_data(globls.arbitrator_sock_eye, globls.arbitrator_sock_addr_eye, data) # print "EYE in or out ", data globls.update_last_sent_eye_in_out(eye_in_out) elif int(cmd_list[0]) == Constant.VERGENCE_REQUEST: points = map(float, cmd_list[1:6]) value = self.eye_check.vergence_error(points) # if value != globls.last_vergence_error_sent: data = '{} {}/'.format(Constant.VERGENCE_STATUS, value) util.send_data(globls.arbitrator_sock_eye, globls.arbitrator_sock_addr_eye, data) # print "Vergence error ", data globls.update_last_sent_vergence_error(value) elif int(cmd_list[0]) == Constant.SCREEN_WINDOW_WIDTH: globls.update_arbitrator_server_screen_resolution(width=int(cmd_list[1])) globls.dump_log('Received the screen width and scale factor to display on GUI: {}'. format(globls.arbitrator_display['x_scale_factor'])) elif int(cmd_list[0]) == Constant.SCREEN_WINDOW_HEIGHT: globls.update_arbitrator_server_screen_resolution(height=int(cmd_list[1])) globls.dump_log('Received the screen Height and scale factor to display on GUI: {}'. format(globls.arbitrator_display['y_scale_factor'])) elif int(cmd_list[0]) == Constant.CENTRE_OF_WINDOWS: # print cmd_list # 100 number list of X Y Z diameter # Maximum 30 points no_of_points = int(cmd_list[1]) config = [] lst = cmd_list[2:] # pair the data and give it to UI for updation for i in range(0, len(lst), 6): config.append([float(lst[i]), float(lst[i + 1]), float(lst[i + 2]), float(lst[i + 3]), lst[i + 4], lst[i + 5]]) if len(config) == Constant.MAXIMUM_CENTRE_OF_WINDOW: break globls.dump_log('Points to draw {}'.format(cmd_list)) globls.update_centre_point(no_of_points, config) elif int(cmd_list[0]) == Constant.WINDOW_ON: # print cmd_list globls.update_centre_window_on_off(True) globls.dump_log('Window On') elif int(cmd_list[0]) == Constant.WINDOW_OFF: # print cmd_list globls.update_centre_window_on_off(False) globls.dump_log('Window Off') # Reset this to -1, -1 so that next time this is queried from # Arbitrator server new values are sent globls.update_last_sent_eye_in_out([-1, -1]) # elif int(cmd_list[0]) == Constant.REWARD_ON: # # print cmd_list # self.DIO_obj.write_digital_bit(1) # #self.DIO_obj.reward_on() # globls.dump_log('Reward On') # elif int(cmd_list[0]) == Constant.REWARD_OFF: # # print cmd_list # self.DIO_obj.write_digital_bit(0) # #self.DIO_obj.reward_off() # globls.dump_log('Reward Off') elif int(cmd_list[0]) == Constant.VERGENCE_ON: # print cmd_list globls.udpdate_vergence_display(True) globls.dump_log('Vergence On') elif int(cmd_list[0]) == Constant.VERGENCE_OFF: # print cmd_list globls.udpdate_vergence_display(False) globls.dump_log('Vergence Off') # Reset this to -1 so that next time this is queried from # Arbitrator server new values are sent globls.update_last_sent_vergence_error(-1) elif int(cmd_list[0]) == Constant.DRAW_EVENTS: tempnum = len(cmd_lists)-1 globls.update_drawing_object_on(1) globls.update_drawing_object_number(tempnum) for i in range(0, tempnum): templist = cmd_lists[i].split() if i == 0: tempx = float(templist[2]) tempy = float(templist[3]) data_str = '6 9 /' temp_data = data_str+"""{}""".format('q'*( 1024 - len(data_str.encode()))) DataFileObj.save_raw_eye_taskdata(data_recv_ts, 0,0,0,0, task_data=temp_data) else: tempx = float(templist[1]) tempy = float(templist[2]) globls.update_drawing_object_pos(i, 0, tempx) globls.update_drawing_object_pos(i, 1, tempy) # elif int(cmd_list[0]) == Constant.EVENTS: # globls.dump_log('event {}'.format(cmd_list)) # if not globls.DUMP_DATA_CONTINUALLY: # if int(cmd_list[1]) == Constant.EVENT_START: # # Start the data save # DataFileObj.update_data_collect_flag(True) # # elif int(cmd_list[1]) == Constant.EVENT_STOP: # # This needs to be saved here as we dump the saved data to file # # And data collection falg will be reset # DataFileObj.save_raw_eye_taskdata( # data_recv_ts, # globls.last_raw_eye_data[0], globls.last_raw_eye_data[1], # globls.last_raw_eye_data[2], globls.last_raw_eye_data[3], # task_data=data) # # # Stop saving the data and dump tp file # # Flag to stop saving the data is set inside this function # DataFileObj.dump_data_to_file() # globls.update_last_sent_vergence_error(-1) # globls.update_last_sent_eye_in_out([-1, -1]) # Save the data from 3rd party server if globls.DUMP_DATA_CONTINUALLY: DataFileObj.dump_data_continually(data_recv_ts, data) # except socket.timeout: # pass except Exception as e: log.exception(e) globls.arbitrator_sock.close()
def analog_reader(self): analog_module = importlib.import_module('analog') analog = getattr(module, 'Analog') ''' Read the eye data from Analog device :return: ''' try: globls.dump_log("Initiated Analog eye data reader") self.analog_reader_obj = analog() while globls.is_program_running: time.sleep(.001) eye_closed = False pupilsize_left, pupilsize_right = 2000, 2000 temp_eye_data = [] temp_eye_pos_channel_data = globls.eye_recording_method_obj.get_eye_positions_channel( ) for channel in temp_eye_pos_channel_data: temp_eye_data.append( self.analog_reader_obj.get_channel_analog_value( int(channel))) eye_recv_data_ts = time.time() eyepos_lx, eyepos_ly = temp_eye_data[0], temp_eye_data[1] eyepos_rx, eyepos_ry = temp_eye_data[0], temp_eye_data[1] # Do not update values if eye is closed or if eye is not avaialble if (pupilsize_left < globls.pupil_size['left'] or pupilsize_right < globls.pupil_size['right']): eye_closed = True # Write eye data to list storing left and right X, Y and Z data # data that we get from eyelink has only left and right eye globls.update_last_raw_eye_data(eyepos_lx, eyepos_ly, eyepos_rx, eyepos_ry) DataFileObj.save_raw_eye_taskdata(eye_recv_data_ts, eyepos_lx, eyepos_ly, eyepos_rx, eyepos_ry) # Get the mean of the raw eye data and later apply offset gain for the mean data left_mean_x, left_mean_y, right_mean_x, right_mean_y = \ self.update_getmean_eye_sample(eyepos_lx, eyepos_ly, eyepos_rx, eyepos_ry, eye_closed) # apply offset and gain left_og_x, left_og_y, right_og_x, right_og_y = \ self.get_offset_gain_applied_eye_data(left_mean_x, left_mean_y, right_mean_x, right_mean_y) globls.update_offset_gain_applied_eye_data( left_og_x, left_og_y, right_og_x, right_og_y) # If eye closed, then do not check eye in out if eye_closed: return # Validate the eye is in or out depending on the task self.eye_check.eye_in_out() except Exception as e: log.exception(e)
def digital_reader(self): pylink = importlib.import_module('pylink') ''' Read the eye data from eyelink :return: ''' try: self.EyeTrack = pylink.EyeLink( globls.config_param['eyelink_service']['ip']) self.EyeTrack.sendCommand( "link_sample_data = LEFT,RIGHT,GAZE,AREA") self.EyeTrack.startRecording(0, 0, 1, 1) globls.dump_log("Initiated digital eye data reader") last_read_eye_time = 0 while globls.is_program_running: # Sleep for 1 ms time.sleep(.001) dt = self.EyeTrack.getNewestSample( ) # check for new sample update eye_recv_data_ts = time.time() if dt is not None: cur_eye_time = dt.getTime() if float(cur_eye_time) != float(last_read_eye_time): eye_closed = False lx = ly = rx = ry = 0 if dt.getRightEye() and dt.getLeftEye(): lx, ly = dt.getLeftEye().getGaze() rx, ry = dt.getRightEye().getGaze() elif dt.getRightEye() and not dt.getLeftEye(): rx, ry = dt.getRightEye().getGaze() lx, ly = rx, ry elif dt.getLeftEye() and not dt.getRightEye(): lx, ly = dt.getLeftEye().getGaze() rx, ry = lx, ly pupilsize_left = dt.getLeftEye().getPupilSize() pupilsize_right = dt.getRightEye().getPupilSize() # # Do not update values if eye is closed or if eye is not avaialble # if (pupilsize_left < globls.pupil_size['left'] or # pupilsize_right > globls.pupil_size['right']): # eye_closed = True # print pupilsize_left, globls.pupil_size['right'] # convert this to coordinate (0, 0) at center eyepos_lx, eyepos_ly = util.shift_to_centre(lx, ly) eyepos_lx, eyepos_ly = util.convert_pix_to_mm( eyepos_lx, eyepos_ly) # convert this to coordinate (0, 0) at center eyepos_rx, eyepos_ry = util.shift_to_centre(rx, ry) eyepos_rx, eyepos_ry = util.convert_pix_to_mm( eyepos_rx, eyepos_ry) # Write eye data to list storing left and right X, Y and Z data # data that we get from eyelink has only left and right eye globls.update_last_raw_eye_data( eyepos_lx, eyepos_ly, eyepos_rx, eyepos_ry) DataFileObj.save_raw_eye_taskdata( eye_recv_data_ts, eyepos_lx, eyepos_ly, eyepos_rx, eyepos_ry) # Get the mean of the raw eye data and later apply offset gain for the mean data left_mean_x, left_mean_y, right_mean_x, right_mean_y = \ self.update_getmean_eye_sample(eyepos_lx, eyepos_ly, eyepos_rx, eyepos_ry, eye_closed) # apply offset and gain left_og_x, left_og_y, right_og_x, right_og_y = \ self.get_offset_gain_applied_eye_data(left_mean_x, left_mean_y, right_mean_x, right_mean_y) # update the offset and gain applied for drawing eye on canvas globls.update_offset_gain_applied_eye_data( left_og_x, left_og_y, right_og_x, right_og_y) # If eye closed, then do not check eye in out or vergence error if eye_closed: return # Validate the eye is in or out depending on the task self.eye_check.eye_in_out() # print "Eye position ", eyepos_lx, left_mean_x, left_og_x last_read_eye_time = cur_eye_time except Exception as e: log.exception(e) globls.dump_log( 'Exception reading eye link data from eyelink tracker {}'. format(e))
def vergence_error(self, target_pt_data): '''' Validate the vergence ''' left_eye_x = globls.eye_data[const.LEFT][0] left_eye_y = globls.eye_data[const.LEFT][1] right_eye_x = globls.eye_data[const.RIGHT][0] right_eye_y = globls.eye_data[const.RIGHT][1] x = target_pt_data[0] y = target_pt_data[1] z = target_pt_data[2] vergence = target_pt_data[3] vergence_option = int(target_pt_data[4]) vergence_error_in_limit = 1 iod = globls.arbitrator_display['iod_mm'] screendist = globls.arbitrator_display['screen_distance_mm'] # Get the target point information for which the vergence needs to be verified left_tp_x, left_tp_y, right_tp_x, right_tp_y = \ util.get_disparity_offset_applied_points(x, y, z) # print left_tp_x, left_tp_y, right_tp_x, right_tp_y # CALCULATE IDEAL GAZE ANGLES # By this convention, looking straight ahead is 0 degrees, looking towards # your nose is negative, looking away from your nose is positive. Fixation # on a point along the gaze direction of the cyclopean eye looking straight # ahead will give you the same coordinate for left & right eyes. # Calculate in degrees # perfect_theta_lx = math.degrees(math.atan2(-(left_tp_x + (iod / 2)), screendist)) perfect_theta_rx = math.degrees(math.atan2((right_tp_x - (iod / 2)), screendist)) perfect_delta_x = perfect_theta_lx + perfect_theta_rx # Calculate the actual values of x using eye data in degrees actual_theta_lx = math.degrees(math.atan2(-(left_eye_x + (iod / 2)), screendist)) actual_theta_rx = math.degrees(math.atan2((right_eye_x - (iod / 2)), screendist)) # Calculate the actual values of y using eye data in degrees actual_theta_ly = 90 - math.degrees(math.atan2(screendist, left_eye_y)) actual_theta_ry = 90 - math.degrees(math.atan2(screendist, right_eye_y)) # CALCULATE ERRORS actual_delta_x = actual_theta_lx + actual_theta_rx vergence_error_x = actual_delta_x - perfect_delta_x # print actual_delta_x, perfect_delta_x vergence_error_y = 0 if vergence_option == Vergence.HORTIZONTAL_VERTICAL: vergence_error_y = actual_theta_ly - actual_theta_ry vergence_magnitude_error = math.sqrt( ((vergence_error_x) ** 2) + (vergence_error_y ** 2)) else: vergence_magnitude_error = math.sqrt(((vergence_error_x) ** 2)) # Method 2 # vergence_magnitude_error = math.sqrt((left_eye[const.X]-left_tp_eye[0]) ** 2 + # (right_eye[const.X]-right_tp_eye[0]) ** 2) # vergence_error_x = vergence_magnitude_error # vergence_error_y = 0 if (vergence_magnitude_error > vergence/2): # Send vergence not in specified limit vergence_error_in_limit = 0 # Update x, y value to plot globls.update_vergence_error_to_plot(vergence_error_x, vergence_error_y, vergence) return vergence_error_in_limit