Skip to content
3 changes: 2 additions & 1 deletion Task/Classes/al_cannon.m
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@
if self.defaultParticles == false
self.dotCol = nan;
else
self.dotCol = load('dotColDefault.mat').dotColDefault;
% self.dotCol = load('dotColDefault.mat').dotColDefault;
self.dotCol = getfield(load('dotColDefault.mat','dotColDefault'),'dotColDefault');
end

end
Expand Down
139 changes: 96 additions & 43 deletions Task/Classes/al_eyeTracker.m
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
ppd % estimated pixels per degree
resolutionX % x resolution (in pixels)
saccThres % threshold value
el %eyetracker instance

end

Expand Down Expand Up @@ -45,7 +46,7 @@
self.saccThres = 1;
end

function self = initializeEyeLink(self, taskParam, et_file_name_suffix)
function self = initializeEyeLink(self, taskParam, et_file_name_suffix)
% INITIALIZEEYELINK This function initialzes the eye-tracker
%
% Input
Expand All @@ -55,24 +56,61 @@
% Output:
% el: Eye-link object


self.et_file_name = sprintf('%s%s', taskParam.subject.ID, et_file_name_suffix);
self.et_file_name = [self.et_file_name]; % todo: check if this is really necessary

% Todo test if we can also pass object instead instead of new structure
options.dist = self.dist;
options.width = self.width;
options.height = self.height;
options.window_rect = taskParam.display.windowRect;
options.frameDur = self.frameDur;
options.frameRate = self.frameRate;
[el, ~] = ELconfig(taskParam.display.window.onScreen, self.et_file_name, options);

% Calibrate the eye tracker
EyelinkDoTrackerSetup(el);

if isequal(taskParam.gParam.trackerVersion, 'eyelink')
% Todo test if we can also pass object instead instead of new structure
options.dist = self.dist;
options.width = self.width;
options.height = self.height;
options.window_rect = taskParam.display.windowRect;
options.frameDur = self.frameDur;
options.frameRate = self.frameRate;
[el, ~] = ELconfig(taskParam.display.window.onScreen, self.et_file_name, options);

% Calibrate the eye tracker
EyelinkDoTrackerSetup(el);

elseif isequal(taskParam.gParam.trackerVersion, 'SMI')
settings = SMITE.getDefaults('HiSpeed');
settings.connectInfo = {'192.168.1.1',4444,'192.168.1.2',5555};
settings.doAverageEyes = false;
settings.cal.bgColor = taskParam.colors.background;
settings.freq = 500;
%settings.trackMode = 'MONOCULAR';
settings.trackEye = 'EYE_RIGHT';
settings.logFileName = 'test_log.txt';
settings.save.allowFileTransfer = false;

% initialize SMI
self.el = SMITE(settings);
%self.el = self.el.setDummyMode();
%try a few times in case connection breaks
tries = 0;
while tries <= 6
try
self.el.init();
tries
self.el.calibrate(taskParam.display.window.onScreen, false); % was calibrate(taskParam.display.window.onScreen, false)
break
catch ME
WaitSecs(7);
tries = tries + 1;
if tries <= 6
continue
else
rethrow(ME);
end
end
end
else

error('Please specifiy tracker version as eyelink or SMI')
end
end


function self = estimatePixelsPerDegree(self)
% ESTIMATEPIXELSPERDEGREE This function estimates the number of
% pixels per degree for online saccade detection
Expand Down Expand Up @@ -102,29 +140,35 @@
% sacc: Detected saccades
%
% Credit: Donner lab

% Short break
pause(0.002)

% Extract samples from eye-link
[samples, ~, ~] = Eyelink('GetQueuedData');

% Extract relevant samples depending on tracked eye
if eye==0
x = (samples(14,:)-zero(1))/self.ppd;
y = (samples(16,:)-zero(2))/self.ppd;
else
x = (samples(15,:)-zero(1))/self.ppd;
y = (samples(17,:)-zero(2))/self.ppd;
end
if isequal(taskParam.gParam.trackerVersion, 'eyelink')

% Compute deviation from fixation spot and categorize saccades
d = (x.^2 + y.^2).^.5;
a = d(2:length(d));
if any(a>self.saccThres)
sacc = 1;
else
sacc = 0;
% Short break
pause(0.002)

% Extract samples from eye-link
[samples, ~, ~] = Eyelink('GetQueuedData');

% Extract relevant samples depending on tracked eye
if eye==0
x = (samples(14,:)-zero(1))/self.ppd;
y = (samples(16,:)-zero(2))/self.ppd;
else
x = (samples(15,:)-zero(1))/self.ppd;
y = (samples(17,:)-zero(2))/self.ppd;
end

% Compute deviation from fixation spot and categorize saccades
d = (x.^2 + y.^2).^.5;
a = d(2:length(d));
if any(a>self.saccThres)
sacc = 1;
else
sacc = 0;
end

else
error('online saccades only implemented for eyelink')
end
end
end
Expand All @@ -139,14 +183,23 @@
%
% Output
% taskParam: Task-parameter-object instance


Eyelink('StartRecording');
WaitSecs(0.1);
Eyelink('message', 'Start recording Eyelink');

% Reference time stamp
taskParam.timingParam.ref = GetSecs();
if isequal(taskParam.gParam.trackerVersion, 'eyelink')
Eyelink('StartRecording');
WaitSecs(0.1);
Eyelink('message', 'Start recording Eyelink');

% Reference time stamp
taskParam.timingParam.ref = GetSecs();

elseif isequal(taskParam.gParam.trackerVersion, 'SMI')
taskParam.eyeTracker.el.startRecording()
WaitSecs(0.1);
taskParam.eyeTracker.el.sendMessage('Start recording SMI');

% Reference time stamp
taskParam.timingParam.ref = GetSecs();
end
end

end
end
2 changes: 2 additions & 0 deletions Task/Classes/al_gparam.m
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
scanner % indicates if experiment takes place in scanner
meg % indicates if experiment takes place with MEG
eyeTracker % indicates if experiment takes place with eyeTracker
trackerVersion % selects whether we want eyelink or SMI version
onlineSaccades % indicates if we track saccades during task
uke % indicates uke fMRI scanner
joy % potentially temporary joystick variable
Expand Down Expand Up @@ -136,6 +137,7 @@
self.scanner = false;
self.meg = false;
self.eyeTracker = false;
self.trackerVersion = 'eyelink';
self.uke = false;
self.joy = nan;
self.useResponseThreshold = false;
Expand Down
13 changes: 11 additions & 2 deletions Task/Classes/al_keys.m
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,20 @@
et_path = pwd;
et_file_name = [et_file_name, '.edf'];

al_saveEyelinkData(et_path, et_file_name)
Eyelink('StopRecording');
if isequal(taskParam.gParam.trackerVersion, 'eyelink')

al_saveEyelinkData(et_path, et_file_name)
Eyelink('StopRecording');

elseif isequal(taskParam.gParam.trackerVersion, 'SMI')

al_saveSMIData(taskParam.eyeTracker.el, et_path, et_file_name)
taskParam.eyeTracker.el.stopRecording();
end

end


% Behavioral
if isequal(taskParam.trialflow.saveData, 'true') && exist('taskData', 'var') == true
al_saveData(taskData)
Expand Down
23 changes: 17 additions & 6 deletions Task/Functions/al_baselineArousal.m
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,12 @@ function al_baselineArousal(taskParam, file_name_suffix)

% Presenting trial number at the bottom of the eyetracker display - optional
if taskParam.gParam.eyeTracker && isequal(taskParam.trialflow.exp, 'exp')
Eyelink('command', 'record_status_message "TRIAL %d/%d"', i, 3);
Eyelink('message', 'TRIALID %d', i);
if isequal(taskParam.gParam.trackerVersion, 'eyelink')
Eyelink('command', 'record_status_message "TRIAL %d/%d"', i, 3);
Eyelink('message', 'TRIALID %d', i);
elseif isequal(taskParam.gParam.trackerVersion, 'SMI')
taskParam.eyeTracker.el.sendMessage(sprintf('TRIALID BaseAr %d', i));
end
end

% Only send trigger on first interation
Expand Down Expand Up @@ -75,8 +79,15 @@ function al_baselineArousal(taskParam, file_name_suffix)
% -----------------

if taskParam.gParam.eyeTracker
et_path = pwd;
et_file_name=[taskParam.eyeTracker.et_file_name, '.edf'];
al_saveEyelinkData(et_path, et_file_name)
Eyelink('StopRecording');
if isequal(taskParam.gParam.trackerVersion, 'eyelink')
et_path = pwd;
et_file_name=[taskParam.eyeTracker.et_file_name, '.edf'];
al_saveEyelinkData(et_path, et_file_name)
Eyelink('StopRecording');
elseif isequal(taskParam.gParam.trackerVersion, 'SMI')
et_path = pwd;
et_file_name=[taskParam.eyeTracker.et_file_name, '.edf'];
al_saveSMIData(taskParam.eyeTracker.el, et_path, et_file_name)
taskParam.eyeTracker.el.stopRecording();
end
end
6 changes: 5 additions & 1 deletion Task/Functions/al_sendTrigger.m
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,11 @@

% Send the pupil trigger
if taskParam.gParam.eyeTracker && isequal(taskParam.trialflow.exp, 'exp') || taskParam.gParam.eyeTracker && isequal(taskParam.trialflow.exp, 'passive')
Eyelink('message', num2str(triggerID));
if isequal(taskParam.gParam.trackerVersion, 'eyelink')
Eyelink('message', num2str(triggerID));
elseif isequal(taskParam.gParam.trackerVersion, 'SMI')
taskParam.eyeTracker.el.sendMessage(num2str(triggerID));
end
end

% Send the EEG trigger
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
% Common Confetti Version Configuration Example
%
% Example of how to add local parameter settings as config input to the
% function that runs the task.
%
% It is recommended that you create your own script with the local
% parameter settings so that you can re-use your settings.

%PsychDebugWindowConfiguration(0,0.5);
% Create config structure
config = struct();

% Add desired parameters
config.trialsExp = 47; %47; %default for experiment is 100 for 4 blocks (400), trying 38 trials for 8 blocks (304)
config.nBlocks = 3; %blocks per noise condition, default is 2
config.practTrialsVis = 10; %10
config.practTrialsHid = 20; %20
config.cannonPractCriterion = 4; % criterion cannon practice
config.cannonPractNumOutcomes = 5; % number of trials cannon practice
config.cannonPractFailCrit = 3;
config.passiveViewing = false;
config.passiveViewingPractTrials = 10;
config.baselineFixLength = 0.25;
config.blockIndices = [1 999 999 999]; % we don't have breaks within each block
config.runIntro = true; % true
config.baselineArousal = true; % true;
config.language = 'German'; % 'English';
config.sentenceLength = 80;
config.textSize = 32;
config.vSpacing = 1;
config.headerSize = 50;
config.screenSize = [0 0 1680 1050]*1; % get(0,'MonitorPositions')*1.0;
config.screenNumber = 1;
config.s = 83;
config.enter = 13;
config.five = 15;
config.defaultParticles = true;
config.debug = false;
config.showConfettiThreshold = false;
config.printTiming = true;
config.hidePtbCursor = true;
config.dataDirectory = 'C://Users//Matlab-User//Documents//AdaptiveLearning//DataDirectory'; %'C://Users//Matlab-User//Documents//AdaptiveLearning//DataDirectory'
config.meg = false;
config.scanner = false;
config.eyeTracker = true; %true;
config.trackerVersion = 'SMI'; %set 'eyelink' or 'SMI'
config.onlineSaccades = false;
config.saccThres = 1;
config.useDegreesVisualAngle = true;
config.distance2screen = 740; %700; % defined in mm (for degrees visual angle) and eT
config.screenWidthInMM = 580; % for degrees visual angle and ET
config.screenHeightInMM = 295; %210; % for ET
config.sendTrigger = false;
config.sampleRate = 500; % Sampling rate for EEG
config.port = hex2dec('E050');
config.rotationRadPixel = 140; % 170
config.rotationRadDeg = 3.16; % 2.5
config.customInstructions = true;
config.instructionText = al_commonConfettiInstructionsJena(config.language);
config.noPtbWarnings = false;
config.predSpotCircleTolerance = 2;

if config.sendTrigger
[config.session, ~] = IOPort( 'OpenSerialPort', 'COM3' );
else
config.session = nan;
end

% Run task with config input
RunCommonConfettiVersion(config);
Loading