From fa8661c35611b41223f77da6682a45a40ddcad0a Mon Sep 17 00:00:00 2001 From: marcobarilari Date: Sun, 24 May 2020 22:03:26 +0200 Subject: [PATCH 1/4] fix typo --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 14d4418..42d8b4a 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ -This is List of Crossmodal Perpeption and Plasticity lab (CPP) PsychToolBox (PTB) toolbox. +This is List of Crossmodal Perception and Plasticity lab (CPP) PsychToolBox (PTB) toolbox. Those functions are mostly wrappers around some PTB functions to facilitate their use and to have a codebase to facilitate their reuse. @@ -19,7 +19,7 @@ For instructions see the following links: | Requirements | Used version | |----------------------------------------------------------|--------------| -| [PsychToolBox](http://psychtoolbox.org/) Duuuuhh | >=3.0.14 | +| [PsychToolBox](http://psychtoolbox.org/) Duuuuhh | >=3.0.14 | | [Matlab](https://www.mathworks.com/products/matlab.html) | 201?? | | or [octave](https://www.gnu.org/software/octave/) | 4.? | From 2944353b13f6b209c25060af935ff6d1b4fd29a9 Mon Sep 17 00:00:00 2001 From: marcobarilari Date: Fri, 17 Jul 2020 19:19:29 +0200 Subject: [PATCH 2/4] add eyeTracker function --- eyeTracker.m | 259 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 259 insertions(+) create mode 100755 eyeTracker.m diff --git a/eyeTracker.m b/eyeTracker.m new file mode 100755 index 0000000..8173722 --- /dev/null +++ b/eyeTracker.m @@ -0,0 +1,259 @@ +function [ el, edfFile ] = eyeTracker(input, cfg, expParameters) + +if ~cfg.eyeTracker + + el = []; + +else + + %% Assign parameters + edfFile = expParameters.fileName.eyetracker; + + switch input + + case 'Calibration' +%% +% screenNumber = max(Screen('Screens')); +% gray=GrayIndex(screenNumber); +% [w, wRect]=Screen('OpenWindow',screenNumber, gray); +% Screen('TextSize', w, 32); +% silver=[192 192 192,(w)]; +% dummymode=0; +% +% el=EyelinkInitDefaults(w); +% el.backgroundcolour = silver; +% el.msgfontcolour = BlackIndex(w); +% el.calibrationtargetcolour= BlackIndex(w); +% el.calibrationtargetsize= 1; +% el.calibrationtargetwidth=0.5; +% el.displayCalResults = 1; +% EyelinkUpdateDefaults(el); +% +% if ~EyelinkInit(dummymode, 1) +% fprintf('Eyelink Init aborted.\n'); +% cleanup; % cleanup function +% return; +% end +% +% [~, vs] = Eyelink('GetTrackerVersion'); +% fprintf('Running experiment on a ''%s'' tracker.\n', vs ); +% Eyelink('Command', 'link_sample_data = LEFT,RIGHT,GAZE,AREA'); +% +% edfFile='demo.edf'; +% Eyelink('Openfile', edfFile); +% +% Eyelink('command','screen_pixel_coords = %ld %ld %ld %ld', 0, 0, 0, 0); +% Eyelink('message', 'DISPLAY_COORDS %ld %ld %ld %ld', 0, 0, 0, 0); +% +% Eyelink('command', 'calibration_type = HV5'); +% Eyelink('command', 'generate_default_targets = YES'); +% +% fprintf('Running experiment on a ''%s'' tracker.\n', vs ); +% vsn = regexp(vs,'\d','match'); +% EyelinkDoTrackerSetup(el); +% +% %go back to black screen +% Screen('FillRect', w, [0 0 0]); +% blank_onset=Screen('Flip', w); + + %% STEP 2 + % 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(cfg.win); + + % calibration has silver background with black targets, sound and smaller + % targets + el.backgroundcolour = [192 192 192,(cfg.win)]; + el.msgfontcolour = BlackIndex(cfg.win); + el.calibrationtargetcolour = BlackIndex(cfg.win); + el.calibrationtargetsize = 1; + el.calibrationtargetwidth = 0.5; + el.displayCalResults = 1; + + % call this function for changes to the calibration structure to take + % affect + EyelinkUpdateDefaults(el); + + % STEP 3 + % Initialization of the connection with the Eyelink Gazetracker. + % exit program if this fails. + + % make sure EL is initialized. + ELinit = Eyelink('Initialize'); + if ELinit~=0 + fprintf('Eyelink is not initialized, aborted.\n'); + Eyelink('Shutdown'); + Screen('CloseAll'); + return; + end + + % make sure we're still connected. + ELconnection = Eyelink('IsConnected'); + if ELconnection~=1 + fprintf('Eyelink is not connected, aborted.\n'); + Eyelink('Shutdown'); + Screen('CloseAll'); + return; + end + + [el.v, el.vs] = Eyelink('GetTrackerVersion'); + fprintf('Running experiment on a ''%s'' tracker.\n', el.vs ); + + % make sure that we get gaze data from the Eyelink + Eyelink('Command', 'link_sample_data = LEFT,RIGHT,GAZE,AREA'); + +% % open file to record data to +% if ~exist('eyetracker','dir') +% mkdir('eyetracker') +% end + + fileEDF = 'demo.edf'; + Eyelink('Openfile', fileEDF); + + % STEP 4 + % 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, cfg.winWidth-1, cfg.winHeight-1); +% Eyelink('message', 'DISPLAY_COORDS %ld %ld %ld %ld', 0, 0, cfg.winWidth-1, cfg.winHeight-1); + Eyelink('command','screen_pixel_coords = %ld %ld %ld %ld', 0, 0, 0, 0); + Eyelink('message', 'DISPLAY_COORDS %ld %ld %ld %ld', 0, 0, 0, 0); + + % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % + % DEFAULT CALIBRATION + % set calibration type. + Eyelink('command', 'calibration_type = HV5'); + + % you must send this command with value NO for custom calibration + % you must also reset it to YES for subsequent experiments + Eyelink('command', 'generate_default_targets = YES'); + % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % + +% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % +% % CUSTOM CALIBRATION +% % (SET MANUALLY THE DOTS COORDINATES, HERE FOR 6 DOTS) +% Eyelink('command', 'calibration_type = HV5'); +% % you must send this command with value NO for custom calibration +% % you must also reset it to YES for subsequent experiments +% Eyelink('command', 'generate_default_targets = NO'); +% +% % calibration and validation target locations +% [width, height]=Screen('WindowSize', screenNumber); +% Eyelink('command','calibration_samples = 6'); +% Eyelink('command','calibration_sequence = 0,1,2,3,4,5'); +% Eyelink('command','calibration_targets = %d,%d %d,%d %d,%d %d,%d %d,%d',... +% 640,512, ... %width/2,height/2 +% 640,102, ... %width/2,height*0.1 +% 640,614, ... %width/2,height*0.6 +% 128,341, ... %width*0.1,height*1/3 +% 1152,341 ); %width-width*0.1,height*1/3 +% +% Eyelink('command','validation_samples = 5'); +% Eyelink('command','validation_sequence = 0,1,2,3,4,5'); +% Eyelink('command','validation_targets = %d,%d %d,%d %d,%d %d,%d %d,%d',... +% 640,512, ... %width/2,height/2 +% 640,102, ... %width/2,height*0.1 +% 640,614, ... %width/2,height*0.6 +% 128,341, ... %width*0.1,height*1/3 +% 1152,341 ); %width-width*0.1,height*1/3 +% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % + +% % set parser (conservative saccade thresholds) +% Eyelink('command', 'saccade_velocity_threshold = 35'); +% Eyelink('command', 'saccade_acceleration_threshold = 9500'); + + % set EDF file contents (not clear what this lines are used for) + el.vsn = regexp(el.vs,'\d','match'); % wont work on EL + + % enter Eyetracker camera setup mode, calibration and validation + EyelinkDoTrackerSetup(el); + +% % % do a final check of calibration using driftcorrection +% % % You have to hit esc before return. +% % EyelinkDoDriftCorrection(el); +% +% % % do a final check of calibration using driftcorrection +% % success=EyelinkDoDriftCorrection(el); +% % if success~=1 +% % Eyelink('shutdown'); +% % Screen('CloseAll'); +% % return; +% % end + + case 'StartRecording' + + % STEP 5 + % EyeLink Start recording the block + Eyelink('Command', 'set_idle_mode'); + WaitSecs(0.05); + Eyelink('StartRecording'); + % % here to tag the recording, in the past caused delays during the + % % presentation so I avoided to use it + % Eyelink('message',['TRIALID ',num2str(blocks),'_startTrial']); + + % check recording status, stop display if error + checkrec=Eyelink('checkrecording'); + if(checkrec~=0) + fprintf('\nEyelink is not recording.\n\n'); + Eyelink('Shutdown'); + Screen('CloseAll'); + return; + end + + % record a few samples before we actually start displaying + % otherwise you may lose a few msec of data + WaitSecs(0.1); + + % HERE START THE STIMALTION OF THE BLOCK + % to mark the beginning of the trial + Eyelink('Message', 'SYNCTIME'); + + case 'StopRecordings' + + % STEP 8 + % finish up: stop recording eye-movements, + % EyeLink Stop recording the block + Eyelink('Message', 'BLANK_SCREEN'); + % adds 100 msec of data to catch final events + WaitSecs(0.1); + % close graphics window, close data file and shut down tracker + Eyelink('StopRecording'); + + case 'Shutdown' + + % STEP 6 + % At the end of the experiment, save the edf file and shut down connection + % with Eyelink + + Eyelink('Command', 'set_idle_mode'); + WaitSecs(0.5); + Eyelink('CloseFile'); + + % download data file + try + fprintf('Receiving data file ''%s''\n', fileEdf ); + status=Eyelink('ReceiveFile','',fileEdf); + if status > 0 + fprintf('ReceiveFile status %d\n', status); + end + if 2==exist(fileEdf, 'file') + fprintf('Data file ''%s'' can be found in ''%s''\n', fileEdf, pwd ); + end + catch + fprintf('Problem receiving data file ''%s''\n', fileEdf ); + end + + Eyelink('shutdown'); + Screen('CloseAll'); + + + end + +end From 66600be4ca6b21277b8ff1c8ac6b4a241b6076d0 Mon Sep 17 00:00:00 2001 From: marcobarilari Date: Fri, 17 Jul 2020 19:25:23 +0200 Subject: [PATCH 3/4] add tested and working version --- eyeTracker.m | 176 ++++++++++++++++++++------------------------------- 1 file changed, 68 insertions(+), 108 deletions(-) diff --git a/eyeTracker.m b/eyeTracker.m index 8173722..57621df 100755 --- a/eyeTracker.m +++ b/eyeTracker.m @@ -1,4 +1,4 @@ -function [ el, edfFile ] = eyeTracker(input, cfg, expParameters) +function [ el, edfFile ] = eyeTracker(input, cfg, expParameters, varargin) if ~cfg.eyeTracker @@ -6,67 +6,20 @@ else - %% Assign parameters - edfFile = expParameters.fileName.eyetracker; - switch input case 'Calibration' -%% -% screenNumber = max(Screen('Screens')); -% gray=GrayIndex(screenNumber); -% [w, wRect]=Screen('OpenWindow',screenNumber, gray); -% Screen('TextSize', w, 32); -% silver=[192 192 192,(w)]; -% dummymode=0; -% -% el=EyelinkInitDefaults(w); -% el.backgroundcolour = silver; -% el.msgfontcolour = BlackIndex(w); -% el.calibrationtargetcolour= BlackIndex(w); -% el.calibrationtargetsize= 1; -% el.calibrationtargetwidth=0.5; -% el.displayCalResults = 1; -% EyelinkUpdateDefaults(el); -% -% if ~EyelinkInit(dummymode, 1) -% fprintf('Eyelink Init aborted.\n'); -% cleanup; % cleanup function -% return; -% end -% -% [~, vs] = Eyelink('GetTrackerVersion'); -% fprintf('Running experiment on a ''%s'' tracker.\n', vs ); -% Eyelink('Command', 'link_sample_data = LEFT,RIGHT,GAZE,AREA'); -% -% edfFile='demo.edf'; -% Eyelink('Openfile', edfFile); -% -% Eyelink('command','screen_pixel_coords = %ld %ld %ld %ld', 0, 0, 0, 0); -% Eyelink('message', 'DISPLAY_COORDS %ld %ld %ld %ld', 0, 0, 0, 0); -% -% Eyelink('command', 'calibration_type = HV5'); -% Eyelink('command', 'generate_default_targets = YES'); -% -% fprintf('Running experiment on a ''%s'' tracker.\n', vs ); -% vsn = regexp(vs,'\d','match'); -% EyelinkDoTrackerSetup(el); -% -% %go back to black screen -% Screen('FillRect', w, [0 0 0]); -% blank_onset=Screen('Flip', w); %% STEP 2 % 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(cfg.win); % calibration has silver background with black targets, sound and smaller % targets - el.backgroundcolour = [192 192 192,(cfg.win)]; + el.backgroundcolour = [ 192 192 192, (cfg.win)]; el.msgfontcolour = BlackIndex(cfg.win); el.calibrationtargetcolour = BlackIndex(cfg.win); el.calibrationtargetsize = 1; @@ -99,30 +52,30 @@ return; end + % + if ~EyelinkInit(0, 1) + fprintf('Eyelink Init aborted.\n'); + return; + end + + % Open the edf file to write the data + edfFile = 'demo.edf'; + Eyelink('Openfile', edfFile); + [el.v, el.vs] = Eyelink('GetTrackerVersion'); fprintf('Running experiment on a ''%s'' tracker.\n', el.vs ); % make sure that we get gaze data from the Eyelink Eyelink('Command', 'link_sample_data = LEFT,RIGHT,GAZE,AREA'); -% % open file to record data to -% if ~exist('eyetracker','dir') -% mkdir('eyetracker') -% end - - fileEDF = 'demo.edf'; - Eyelink('Openfile', fileEDF); - % STEP 4 % 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'''); + % 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, cfg.winWidth-1, cfg.winHeight-1); -% Eyelink('message', 'DISPLAY_COORDS %ld %ld %ld %ld', 0, 0, cfg.winWidth-1, cfg.winHeight-1); Eyelink('command','screen_pixel_coords = %ld %ld %ld %ld', 0, 0, 0, 0); Eyelink('message', 'DISPLAY_COORDS %ld %ld %ld %ld', 0, 0, 0, 0); @@ -136,38 +89,38 @@ Eyelink('command', 'generate_default_targets = YES'); % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % -% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % -% % CUSTOM CALIBRATION -% % (SET MANUALLY THE DOTS COORDINATES, HERE FOR 6 DOTS) -% Eyelink('command', 'calibration_type = HV5'); -% % you must send this command with value NO for custom calibration -% % you must also reset it to YES for subsequent experiments -% Eyelink('command', 'generate_default_targets = NO'); -% -% % calibration and validation target locations -% [width, height]=Screen('WindowSize', screenNumber); -% Eyelink('command','calibration_samples = 6'); -% Eyelink('command','calibration_sequence = 0,1,2,3,4,5'); -% Eyelink('command','calibration_targets = %d,%d %d,%d %d,%d %d,%d %d,%d',... -% 640,512, ... %width/2,height/2 -% 640,102, ... %width/2,height*0.1 -% 640,614, ... %width/2,height*0.6 -% 128,341, ... %width*0.1,height*1/3 -% 1152,341 ); %width-width*0.1,height*1/3 -% -% Eyelink('command','validation_samples = 5'); -% Eyelink('command','validation_sequence = 0,1,2,3,4,5'); -% Eyelink('command','validation_targets = %d,%d %d,%d %d,%d %d,%d %d,%d',... -% 640,512, ... %width/2,height/2 -% 640,102, ... %width/2,height*0.1 -% 640,614, ... %width/2,height*0.6 -% 128,341, ... %width*0.1,height*1/3 -% 1152,341 ); %width-width*0.1,height*1/3 -% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % - -% % set parser (conservative saccade thresholds) -% Eyelink('command', 'saccade_velocity_threshold = 35'); -% Eyelink('command', 'saccade_acceleration_threshold = 9500'); + % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % + % % CUSTOM CALIBRATION + % % (SET MANUALLY THE DOTS COORDINATES, HERE FOR 6 DOTS) + % Eyelink('command', 'calibration_type = HV5'); + % % you must send this command with value NO for custom calibration + % % you must also reset it to YES for subsequent experiments + % Eyelink('command', 'generate_default_targets = NO'); + % + % % calibration and validation target locations + % [width, height]=Screen('WindowSize', screenNumber); + % Eyelink('command','calibration_samples = 6'); + % Eyelink('command','calibration_sequence = 0,1,2,3,4,5'); + % Eyelink('command','calibration_targets = %d,%d %d,%d %d,%d %d,%d %d,%d',... + % 640,512, ... %width/2,height/2 + % 640,102, ... %width/2,height*0.1 + % 640,614, ... %width/2,height*0.6 + % 128,341, ... %width*0.1,height*1/3 + % 1152,341 ); %width-width*0.1,height*1/3 + % + % Eyelink('command','validation_samples = 5'); + % Eyelink('command','validation_sequence = 0,1,2,3,4,5'); + % Eyelink('command','validation_targets = %d,%d %d,%d %d,%d %d,%d %d,%d',... + % 640,512, ... %width/2,height/2 + % 640,102, ... %width/2,height*0.1 + % 640,614, ... %width/2,height*0.6 + % 128,341, ... %width*0.1,height*1/3 + % 1152,341 ); %width-width*0.1,height*1/3 + % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % + + % % set parser (conservative saccade thresholds) + % Eyelink('command', 'saccade_velocity_threshold = 35'); + % Eyelink('command', 'saccade_acceleration_threshold = 9500'); % set EDF file contents (not clear what this lines are used for) el.vsn = regexp(el.vs,'\d','match'); % wont work on EL @@ -175,17 +128,21 @@ % enter Eyetracker camera setup mode, calibration and validation EyelinkDoTrackerSetup(el); -% % % do a final check of calibration using driftcorrection -% % % You have to hit esc before return. -% % EyelinkDoDriftCorrection(el); -% -% % % do a final check of calibration using driftcorrection -% % success=EyelinkDoDriftCorrection(el); -% % if success~=1 -% % Eyelink('shutdown'); -% % Screen('CloseAll'); -% % return; -% % end + % % % do a final check of calibration using driftcorrection + % % % You have to hit esc before return. + % % EyelinkDoDriftCorrection(el); + % + % % % do a final check of calibration using driftcorrection + % % success=EyelinkDoDriftCorrection(el); + % % if success~=1 + % % Eyelink('shutdown'); + % % Screen('CloseAll'); + % % return; + % % end + + % Go back to black screen + Screen('FillRect', cfg.win, [0 0 0]); + Screen('Flip', cfg.win); case 'StartRecording' @@ -228,6 +185,9 @@ case 'Shutdown' + edfFileName = expParameters.fileName.eyetracker; + edfFile = 'demo.edf'; + % STEP 6 % At the end of the experiment, save the edf file and shut down connection % with Eyelink @@ -238,16 +198,16 @@ % download data file try - fprintf('Receiving data file ''%s''\n', fileEdf ); - status=Eyelink('ReceiveFile','',fileEdf); + fprintf('Receiving data file ''%s''\n', edfFileName ); + status=Eyelink('ReceiveFile','',[expParameters.outputDir, filesep, 'eyetracker', filesep, edfFileName]); if status > 0 fprintf('ReceiveFile status %d\n', status); end - if 2==exist(fileEdf, 'file') - fprintf('Data file ''%s'' can be found in ''%s''\n', fileEdf, pwd ); + if 2==exist([expParameters.outputDir, filesep, 'eyetracker', filesep, edfFileName], 'file') + fprintf('Data file ''%s'' can be found in ''%s''\n', edfFileName, [expParameters.outputDir, filesep, 'eyetracker', filesep] ); end catch - fprintf('Problem receiving data file ''%s''\n', fileEdf ); + fprintf('Problem receiving data file ''%s''\n', edfFileName ); end Eyelink('shutdown'); From a603326daa2ee3d7a58bada31825884f743dc9f4 Mon Sep 17 00:00:00 2001 From: marcobarilari Date: Fri, 17 Jul 2020 19:32:41 +0200 Subject: [PATCH 4/4] add short documentation --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 011ceeb..6d34987 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,10 @@ and returns a structure with an additional field with Pix suffix holding that ne Define the parameters of the fixation cross in `cfg` and `expParameters` and this does the rest. +### eyeTracker + +This will handle the Eye Tracker (EyeLink set up) and can be called to initialize the connection and start the calibration, start/stop eye(s) movement recordings and save the `*.edf` file (named with BIDS specification from cpp-lln-lab/CPP_BIDS). + ### pressSpace4me Use that to stop your script and only restart when the space bar is pressed.