function EyelinkFixationWindow % % ___________________________________________________________________ % % Demo implemetation of detecting eye in fixation window on display % computer through samples from the tracker % % stimulus: A fixation dot % % This task demonstrates stimuli presentation with Eyelink and Data Viewer % integration. % % press space to end experiment % ___________________________________________________________________ % HISTORY % mm/dd/yy % % 01/28/11 NJ created % 12/20/13 LJ fixed issue with non integer arguments for Eyelink('message' ...) % changed EyeLink to Eyelink , case sensitive for the latest matlab PsychDefaultSetup(1); % trial defaults dummymode=0; if ~IsOctave commandwindow; else more off; end stopkey=KbName('space'); firstRun = 1; infix=0; dotSize = 10; fixWinSize = 100; imageList = {'HappyFace.jpg' 'SadFace.jpg'}; %[versionString, versionStructure]=PsychtoolboxVersion; try %%%%%%%%%% % STEP 1 % %%%%%%%%%% % Added a dialog box to set your own EDF file name before opening % experiment graphics. Make sure the entered EDF file name is 1 to 8 % characters in length and only numbers or letters are allowed. if IsOctave edfFile = 'DEMO'; else prompt = {'Enter tracker EDF file name (1 to 8 letters or numbers)'}; dlg_title = 'Create EDF file'; num_lines= 1; def = {'DEMO'}; answer = inputdlg(prompt,dlg_title,num_lines,def); edfFile = answer{1}; fprintf('EDFFile: %s\n', edfFile ); end %%%%%%%%%% % STEP 2 % %%%%%%%%%% % Open a graphics window on the main screen % using the PsychToolbox's Screen function. screenNumber=max(Screen('Screens')); [window, wRect]=Screen('OpenWindow', screenNumber, 0,[],32,2); Screen(window,'BlendFunction',GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); [winWidth, winHeight] = WindowSize(window); % create fixation dot and fixation window rectangles fixationDot = [-dotSize -dotSize dotSize dotSize]; fixationDot = CenterRect(fixationDot, wRect); fixationWindow = [-fixWinSize -fixWinSize fixWinSize fixWinSize]; fixationWindow = CenterRect(fixationWindow, wRect); % make textures happy = Screen('MakeTexture',window, imread(char(imageList(1)))); sad = Screen('MakeTexture',window, imread(char(imageList(2)))); %%%%%%%%%% % STEP 3 % %%%%%%%%%% % Provide Eyelink with details about the graphics environment % and perform some initializations. The information is returned % in a structure that also contains useful defaults % and control codes (e.g. tracker state bit and Eyelink key values). el=EyelinkInitDefaults(window); % We are changing calibration to a black background with white targets, % no sound and smaller targets el.backgroundcolour = BlackIndex(el.window); el.msgfontcolour = WhiteIndex(el.window); el.imgtitlecolour = WhiteIndex(el.window); el.targetbeep = 0; el.calibrationtargetcolour = WhiteIndex(el.window); % for lower resolutions you might have to play around with these values % a little. If you would like to draw larger targets on lower res % settings please edit PsychEyelinkDispatchCallback.m and see comments % in the EyelinkDrawCalibrationTarget function el.calibrationtargetsize= 1; el.calibrationtargetwidth=0.5; % call this function for changes to the calibration structure to take % affect EyelinkUpdateDefaults(el); %%%%%%%%%% % STEP 4 % %%%%%%%%%% % Initialization of the connection with the Eyelink Gazetracker. % exit program if this fails. if ~EyelinkInit(dummymode) fprintf('Eyelink Init aborted.\n'); cleanup; % cleanup function return; end % open file to record data to i = Eyelink('Openfile', edfFile); if i~=0 fprintf('Cannot create EDF file ''%s'' ', edffilename); cleanup; return; end % make sure we're still connected. if Eyelink('IsConnected')~=1 && ~dummymode cleanup; return; end; %%%%%%%%%% % STEP 5 % %%%%%%%%%% % SET UP TRACKER CONFIGURATION % Setting the proper recording resolution, proper calibration type, % as well as the data file content; Eyelink('command', 'add_file_preamble_text ''Recorded by EyelinkToolbox demo-experiment'''); % This command is crucial to map the gaze positions from the tracker to % screen pixel positions to determine fixation Eyelink('command','screen_pixel_coords = %ld %ld %ld %ld', 0, 0, winWidth-1, winHeight-1); Eyelink('message', 'DISPLAY_COORDS %ld %ld %ld %ld', 0, 0, winWidth-1, winHeight-1); % set calibration type. Eyelink('command', 'calibration_type = HV9'); Eyelink('command', 'generate_default_targets = YES'); % set parser (conservative saccade thresholds) Eyelink('command', 'saccade_velocity_threshold = 35'); Eyelink('command', 'saccade_acceleration_threshold = 9500'); % set EDF file contents % 5.1 retrieve tracker version and tracker software version [v,vs] = Eyelink('GetTrackerVersion'); fprintf('Running experiment on a ''%s'' tracker.\n', vs ); vsn = regexp(vs,'\d','match'); if v ==3 && str2double(vsn{1}) == 4 % if EL 1000 and tracker version 4.xx % remote mode possible add HTARGET ( head target) Eyelink('command', 'file_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON,INPUT'); Eyelink('command', 'file_sample_data = LEFT,RIGHT,GAZE,HREF,AREA,GAZERES,STATUS,INPUT,HTARGET'); % set link data (used for gaze cursor) Eyelink('command', 'link_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON,FIXUPDATE,INPUT'); Eyelink('command', 'link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS,INPUT,HTARGET'); else Eyelink('command', 'file_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON,INPUT'); Eyelink('command', 'file_sample_data = LEFT,RIGHT,GAZE,HREF,AREA,GAZERES,STATUS,INPUT'); % set link data (used for gaze cursor) Eyelink('command', 'link_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON,FIXUPDATE,INPUT'); Eyelink('command', 'link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS,INPUT'); end % calibration/drift correction target Eyelink('command', 'button_function 5 "accept_target_fixation"'); %%%%%%%%%% % STEP 6 % %%%%%%%%%% if ~dummymode % Hide the mouse cursor and setup the eye calibration window Screen('HideCursorHelper', window); end % enter Eyetracker camera setup mode, calibration and validation EyelinkDoTrackerSetup(el); %%%%%%%%% % STEP 7% %%%%%%%%% % Now starts running individual trials % You can keep the rest of the code except for the implementation % of graphics and event monitoring % Each trial should have a pair of "StartRecording" and "StopRecording" % calls as well integration messages to the data file (message to mark % the time of critical events and the image/interest area/condition % information for the trial) trial = 1; numTrials = 3; index = 1; % repeat until we have 3 sucessful trials while trial <= numTrials % wait a second between trials WaitSecs(1); % STEP 7.1 % Sending a 'TRIALID' message to mark the start of a trial in Data % Viewer. This is different than the start of recording message % START that is logged when the trial recording begins. The viewer % will not parse any messages, events, or samples, that exist in % the data file prior to this message. Eyelink('Message', 'TRIALID %d', trial); % This supplies the title at the bottom of the eyetracker display Eyelink('command', 'record_status_message "TRIAL %d/%d"', trial,numTrials); Eyelink('Command', 'set_idle_mode'); % clear tracker display and draw box at center Eyelink('Command', 'clear_screen %d', 0); % draw fixation and fixation window shapes on host PC Eyelink('command', 'draw_cross %d %d 15', winWidth/2,winHeight/2); Eyelink('command', 'draw_box %d %d %d %d 15', fixationWindow(1), fixationWindow(2), fixationWindow(3), fixationWindow(4)); % STEP 7.2 % Do a drift correction at the beginning of each trial % Performing drift correction (checking) is optional for % EyeLink 1000 eye trackers. Drift correcting at different % locations x and y depending on where the ball will start % we change the location of the drift correction to match that of % the target start position EyelinkDoDriftCorrection(el); % STEP 7.3 % start recording eye position (preceded by a short pause so that % the tracker can finish the mode transition) % The paramerters for the 'StartRecording' call controls the % file_samples, file_events, link_samples, link_events availability Eyelink('Command', 'set_idle_mode'); WaitSecs(0.05); Eyelink('StartRecording'); eye_used = Eyelink('EyeAvailable'); % get eye that's tracked % returns 0 (LEFT_EYE), 1 (RIGHT_EYE) or 2 (BINOCULAR) depending on what data is if eye_used == 2 eye_used = 1; % use the right_eye data end % record a few samples before we actually start displaying % otherwise you may lose a few msec of data WaitSecs(0.1); % STEP 7.4 % Prepare and show the screen. Screen('BlendFunction', window, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); Screen('FillRect', window, el.backgroundcolour); Screen('FillOval', window,round([rand*255 rand*255 rand*255]), fixationDot); Screen('Flip',window); Eyelink('Message', 'SYNCTIME'); % get screen image from the first display to use as Data Viewer % trial overlay. Note this call is very slow and will affect your % timing for the first screen blanking if firstRun imageArray = Screen('GetImage', window); firstRun =0; end % set fixation display to be randomly chose between 650 and 1500 fixateTime = GetSecs + round(650 + (1500-650).*rand)/1000 + 200/1000; graceTime = GetSecs + 200/1000; while GetSecs < fixateTime if dummymode==0 error=Eyelink('CheckRecording'); if(error~=0) break; end if Eyelink( 'NewFloatSampleAvailable') > 0 % get the sample in the form of an event structure evt = Eyelink( 'NewestFloatSample'); evt.gx evt.gy if eye_used ~= -1 % do we know which eye to use yet? % if we do, get current gaze position from sample x = evt.gx(eye_used+1); % +1 as we're accessing MATLAB array y = evt.gy(eye_used+1); % do we have valid data and is the pupil visible? if x~=el.MISSING_DATA && y~=el.MISSING_DATA && evt.pa(eye_used+1)>0 mx=x; my=y; end end end else % Query current mouse cursor position (our "pseudo-eyetracker") - % (mx,my) is our gaze position. [mx, my]=GetMouse(window); %#ok<*NASGU> end if infixationWindow(mx,my) && ~infix Eyelink('Message', 'Fixation Start'); Beeper(el.calibration_success_beep(1), el.calibration_success_beep(2), el.calibration_success_beep(3)); infix = 1; elseif ~infixationWindow(mx,my) && infix && GetSecs > graceTime Screen('DrawTexture', window, sad); Screen('Flip',window); disp('broke fix'); Eyelink('Message', 'Fixation broke or grace time ended'); Beeper(el.calibration_failed_beep(1), el.calibration_failed_beep(2), el.calibration_failed_beep(3)); infix = 0; break; end [keyIsDown,secs,keyCode] = KbCheck; %#ok<*ASGLU> % if spacebar was pressed stop display if keyCode(stopkey ) sprintf('Space pressed, exiting trial\n'); Eyelink('Message', 'Key pressed'); break; end end if infix Screen('DrawTexture', window, happy); Screen('Flip',window); sprintf('Trial completed. Trial %d of %d\n', trial, numTrials); trial = trial + 1; WaitSecs(1); end % STEP 7.5 % add 100 msec of data to catch final events and blank display WaitSecs(0.1); Eyelink('StopRecording'); index = index + 1; Screen('FillRect', window, el.backgroundcolour); Screen('Flip', window); imwrite(imageArray, 'imgfile.jpg', 'jpg'); Eyelink('Message', '!V IMGLOAD CENTER %s %d %d', 'imgfile.jpg', winWidth/2, winHeight/2); % STEP 7.6 % Send out necessary integration messages for data analysis % Send out interest area information for the trial % See "Protocol for EyeLink Data to Viewer Integration-> Interest % Area Commands" section of the EyeLink Data Viewer User Manual % IMPORTANT! Don't send too many messages in a very short period of % time or the EyeLink tracker may not be ablwWe to write them all % to the EDF file. % Consider adding a short delay every few messages. WaitSecs(0.001); Eyelink('Message', '!V IAREA ELLIPSE %d %d %d %d %d %s', 1, floor(winWidth/2-dotSize), floor(winHeight/2-dotSize), floor(winWidth/2+dotSize), floor(winHeight/2+dotSize),'center'); Eyelink('Message', '!V IAREA RECTANGLE %d %d %d %d %d %s', 2, floor(winWidth/2-fixWinSize), floor(winHeight/2-fixWinSize), floor(winWidth/2+fixWinSize), floor(winHeight/2+fixWinSize),'centerWin'); % Send messages to report trial condition information % Each message may be a pair of trial condition variable and its % corresponding value follwing the '!V TRIAL_VAR' token message % See "Protocol for EyeLink Data to Viewer Integration-> Trial % Message Commands" section of the EyeLink Data Viewer User Manual WaitSecs(0.001); Eyelink('Message', '!V TRIAL_VAR index %d', index); Eyelink('Message', '!V TRIAL_VAR imgfile %s', 'imgfile.jpg'); if infix Eyelink('Message', '!V TRIAL_VAR trialOutcome %s', 'succesful'); else Eyelink('Message', '!V TRIAL_VAR trialOutcome %s', 'recycled'); end % STEP 9 % Sending a 'TRIAL_RESULT' message to mark the end of a trial in % Data Viewer. This is different than the end of recording message % END that is logged when the trial recording ends. The viewer will % not parse any messages, events, or samples that exist in the data % file after this message. Eyelink('Message', 'TRIAL_RESULT 0'); end %%%%%%%%%% % STEP 8 % %%%%%%%%%% % End of Experiment; close the file first % close graphics window, close data file and shut down tracker Screen('CloseAll'); Eyelink('Command', 'set_idle_mode'); WaitSecs(0.5); Eyelink('CloseFile'); % download data file try fprintf('Receiving data file ''%s''\n', edfFile ); status=Eyelink('ReceiveFile'); if status > 0 fprintf('ReceiveFile status %d\n', status); end if 2==exist(edfFile, 'file') fprintf('Data file ''%s'' can be found in ''%s''\n', edfFile, pwd ); end catch %#ok<*CTCH> fprintf('Problem receiving data file ''%s''\n', edfFile ); end %%%%%%%%%% % STEP 9 % %%%%%%%%%% % run cleanup function (close the eye tracker and window). cleanup; catch cleanup; fprintf('%s: some error occured\n', mfilename); psychrethrow(lasterror); %#ok<*LERR> end function cleanup % Shutdown Eyelink: Eyelink('Shutdown'); Screen('CloseAll'); end function fix = infixationWindow(mx,my) % determine if gx and gy are within fixation window fix = mx > fixationWindow(1) && mx < fixationWindow(3) && ... my > fixationWindow(2) && my < fixationWindow(4) ; end end