Skip to content

Commit

Permalink
swap x y, upper-case Eyelink, add functional, window screen inside ru…
Browse files Browse the repository at this point in the history
…nExperiment, wait after eyetracker setup to clear screen
  • Loading branch information
mschrimpf committed Jul 29, 2016
1 parent 6d78fe8 commit db10895
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 67 deletions.
18 changes: 11 additions & 7 deletions AwaitGoodFixation.m
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
function [exp_params, hadToRecalibrate] = AwaitGoodFixation(exp_params, ...
window, windowRect, fixationScreen, getKeyInput)
window, windowRect, ...
fixationScreen, fixationSourceRect, fixationDestRect,...
getKeyInput)
%AWAITGOODFIXATION wait for good fixation and recalibrate if necessary
goodFixation = false;
hadToRecalibrate = false;
while(~goodFixation)
goodFixation = fixationPoint(window, fixationScreen, ...
windowRect(3) / 2, windowRect(4) / 2, ...
fixationSourceRect, fixationDestRect, ...
exp_params.fixation_threshold, exp_params.fixation_time, ...
exp_params.fixation_timeout);

Expand Down Expand Up @@ -48,18 +51,19 @@
end

function resultcode = fixationPoint(window, fixationScreen, ...
fixX, fixY, fixAccuracy, fixTime, timeout)
%should probably add in some keyboard awareness here, in case we need to
%cancel or pause or something during fixation.
Screen('DrawTexture',window,fixationScreen);
fixationSourceRect, fixationDestRect, ...
fixAccuracy, fixTime, timeout)
Screen('DrawTexture',window,fixationScreen, fixationSourceRect, fixationDestRect);
Screen('flip',window);
fixOnTime = GetSecs;
fixX = (fixationDestRect(1) + fixationDestRect(3)) / 2;
fixY = (fixationDestRect(2) + fixationDestRect(4)) / 2;

resultcode = 0;
firstGoodTime = -1;
lastGoodTime = -1;
while (GetSecs - fixOnTime < timeout) && (resultcode < 1)
fsample = eyelink('NewestFloatSample');
fsample = Eyelink('NewestFloatSample');
if isstruct(fsample)
gx = max(fsample.gx); %gaze position in pixels - I think whichever eye is not tracked is -32768, so this should pull out the useful position
gy = max(fsample.gy);
Expand Down
92 changes: 92 additions & 0 deletions lib/functional/curry.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@

function func = curry(varargin)
% FUNC = CURRY(N, F, ARGS)
% FUNC = CURRY(F, ARGS)
% Return a curried function of F. If N is given, then N arguments are
% expected for F (otherwise, N is taken to be NARGIN(F)). If N is
% negative, then |N| or more arguments are accepted (but F is invoked as
% soon as there are at least N arguments). ARGS are counted in N. If
% less than N arguments are supplied in total, then a *new* curried
% function involving all arguments so far is returned.
%
% FUNC = CURRY()
% This actually just returns CURRY and is a sort of `base case' for
% currying functions.
%
% FUNC = CURRY(N)
% This returns a function that waits for F to invoke CURRY(N, F, ...).
%

if nargin == 0
func = @curry;
return;
end

arg = varargin{1};
varargin(1) = [];

if isnumeric(arg)
many = arg < 0;
params = abs(arg);
if isempty(varargin)
callback = [];
else
callback = varargin{1};
varargin(1) = [];
end
elseif islambda(arg)
many = true;
params = nargin(arg);
callback = arg;
else
error('Curry:Arguments', 'First argument must be either number of arguments or a function.');
end
args = varargin;
% If not many, then we also know params but not necessarily callback.
if ~many
func = genExactFunc(callback, params, args);
else
func = genManyFunc(callback, params, args);
end
end

% We always return a function, as we don't know what the actual outputs
% call for until an invocation.
% We also don't know if callback is known yet.
function func = genExactFunc(callback, params, args)
function varargout = invokeCallback(varargin)
n = numel(varargin) + numel(args);
if n < params
varargout{1} = genExactFunc(callback, params, [args, varargin]);
elseif n > params
error('Curry:Invocation', 'Function was supposed to be called with exactly %d parameters, but has %d instead.', params, n);
else
varargout{1:nargout} = callback(args{:}, varargin{:});
end
end

function target = invokeCurry(varargin)
target = curry(params, varargin{:});
end

% If we don't know what the callback is yet, just wait and have curry
% figure it out and reinvoke this function.
if isempty(callback)
func = @invokeCurry;
else
func = @invokeCallback;
end
end

function func = genManyFunc(callback, params, args)
function varargout = invokeCallback(varargin)
n = numel(varargin) + numel(args);
if n < params
varargout{1} = genManyFunc(callback, params, [args, varargin]);
else
varargout{1:nargout} = callback(args{:}, varargin{:});
end
end

func = @invokeCallback;
end
9 changes: 9 additions & 0 deletions lib/functional/islambda.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

function b = islambda(a)
% BOOL = ISLAMBDA(VALUE)
% Returns true when VALUE is a function handle, either an explicit lambda
% expression or a named function.
%

b = strcmp(class(a), 'function_handle');
end
106 changes: 58 additions & 48 deletions runExperiment.m
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,6 @@
data.recalibrated = false(0, 1);


% grating
gratingImage = exp_params.grating_image;

% save presentation order to session file
save(sessionFile, 'data', 'exp_params');

Expand All @@ -112,10 +109,20 @@
% the PsychToolbox screen and go back to Matlab command window
% in case of an error
try
[window, windowRect] = Screen('OpenWindow', ...
exp_params.monitor_id, exp_params.background_color);
[window, ScrVars] = GenScreenSetup(exp_params.background_color);
windowRect = ScrVars.winRect;
Priority(MaxPriority(window, 'WaitBlanking'));
windowSize = windowRect(3:4);
exp_params.fixation_position_x = windowSize(1) / 2;
exp_params.fixation_position_y = windowSize(2) / 2;

% grating
ScrWdCm = 70; %
DistToScrCm = 85; %
gratingImageDegrees = 3;
Geo = GKlab_ScreenGeometry(ScrVars.winWidth, ScrWdCm, DistToScrCm);
gratingImage = createGratingImage(gratingImageDegrees, ...
Geo.FovDegPerPix, gray, black);

% background texture
backgroundMatrix = exp_params.background_color * ones(windowSize);
Expand All @@ -130,6 +137,10 @@
exp_params.fixation_size, exp_params.fixation_width, ...
exp_params.background_color, white);
oddFixationScreen = Screen('maketexture', window, oddFixationMatrix);
fixationSourceRect = [0, 0, size(normalFixationMatrix)];
fixationDestRect = CenterRectOnPointd(fixationSourceRect, ...
exp_params.fixation_position_x, ...
exp_params.fixation_position_y);

% grating texture
gratingTexture = Screen('MakeTexture', window, gratingImage);
Expand Down Expand Up @@ -164,15 +175,16 @@

% start experiment
if exp_params.eyelink
eyelink('message', 'EXP_START');
Eyelink('message', 'EXP_START');
end

Screen('DrawTexture', window, backgroundScreen);
Screen('flip', window);

% setup blocks
blockIndex = 1;
score = 0; % counter
imagesPerBlock = ...
exp_params.images_per_sequence * exp_params.sequences_per_block;

% show block 1
Screen('flip', window);
Expand All @@ -192,24 +204,28 @@
trialIter = trialIter + 1;
data.trial(trialIter, 1) = trialIter;
fprintf('Trial %d\n', trialIter);
data.grating_location(trialIter, 1) = prod(windowSize) * rand(1);
[data.grating_location_y(trialIter, 1), ...
data.grating_location_x(trialIter, 1)] = ...
data.fixation_position_x(trialIter, 1) = exp_params.fixation_position_x;
data.fixation_position_y(trialIter, 1) = exp_params.fixation_position_y;
data.grating_position(trialIter, 1) = prod(windowSize) * rand(1);
[data.grating_position_x(trialIter, 1), ...
data.grating_position_y(trialIter, 1)] = ...
ind2sub(windowSize, ...
data.grating_location(trialIter));
data.grating_position(trialIter));
data.odd(trialIter, 1:3) = rand(1, 3) < 0.01;

%% fixation
fixationScreen = getFixationScreen(data.odd(trialIter, 1), ...
normalFixationScreen, oddFixationScreen);
Screen('DrawTexture', window, fixationScreen);
Screen('DrawTexture', window, fixationScreen, ...
fixationSourceRect, fixationDestRect);
Screen('flip', window);
data.recalibrated(trialIter, 1) = false;
% check fixation only every images_per_sequence trials
if mod(trialIter, exp_params.images_per_sequence) == 0
if mod(trialIter - 1, exp_params.images_per_sequence) == 0
if exp_params.eyelink
[exp_params, hadToRecalibrate] = AwaitGoodFixation(exp_params, ...
window, windowRect, fixationScreen, ...
fixationSourceRect, fixationDestRect, ...
curry(@WaitForKeyKeyboard, keyboards,0, exp_params.exit_keys));
data.recalibrated(trialIter, 1) = hadToRecalibrate;
else
Expand All @@ -220,16 +236,16 @@
%% present grating
sourceRect = [0, 0, size(gratingImage)];
destRect = CenterRectOnPointd(sourceRect, ...
data.grating_location_x(trialIter), ...
data.grating_location_y(trialIter));
data.grating_position_x(trialIter), ...
data.grating_position_y(trialIter));
fixationScreen = getFixationScreen(data.odd(trialIter, 2), ...
normalFixationScreen, oddFixationScreen);
Screen('DrawTexture', window, fixationScreen);
Screen('DrawTexture', window, fixationScreen, ...
fixationSourceRect, fixationDestRect);
Screen('DrawTexture', window, gratingTexture, sourceRect, destRect);
vblGratingStart = Screen('flip', window);
if exp_params.eyelink
eyelink('message', sprintf('GRATING_%d ON (/%d)', ...
trialIter, nTrials));
Eyelink('message', sprintf('GRATING_%d ON', trialIter));
end
sendTriggers(triggerDevice, exp_params.num_triggers_image_onoff, ...
exp_params.trigger_duration, exp_params.trigger_interval);
Expand All @@ -238,12 +254,13 @@
fixationScreen = getFixationScreen(data.odd(trialIter, 3), ...
normalFixationScreen, oddFixationScreen);
Screen('DrawTexture', window, backgroundScreen);
Screen('DrawTexture', window, fixationScreen);
Screen('DrawTexture', window, fixationScreen, ...
fixationSourceRect, fixationDestRect);
vblBackgroundStart = Screen('flip', window, ...
vblGratingStart + exp_params.grating_duration - 1 / 60 / 10);
if exp_params.eyelink
eyelink('message', sprintf('GRATING_%d OFF', trialIter));
eyelink('message', sprintf('BACKGROUND_%d ON', trialIter));
Eyelink('message', sprintf('GRATING_%d OFF', trialIter));
Eyelink('message', sprintf('BACKGROUND_%d ON', trialIter));
end
sendTriggers(triggerDevice, exp_params.num_triggers_image_onoff, ...
exp_params.trigger_duration, exp_params.trigger_interval);
Expand All @@ -257,10 +274,8 @@
% off
vblBackgroundEnd = WaitSecs(exp_params.background_duration);
if exp_params.eyelink
eyelink('message', sprintf('BACKGROUND_%d OFF', trialIter));
Eyelink('message', sprintf('BACKGROUND_%d OFF', trialIter));
end
sendTriggers(triggerDevice, exp_params.num_triggers_image_onoff, ...
exp_params.trigger_duration, exp_params.trigger_interval);
data.backgroundPresentationDuration(trialIter, 1) = ...
vblBackgroundEnd - vblBackgroundStart;

Expand All @@ -283,14 +298,11 @@
exp_params.r_keys == data.responseKey(trialIter), ...
1, 'first'));
assert(~isnan(data.response(trialIter)));

data.truth(trialIter, 1) = any(any(data.odd(trialIter - ...
exp_params.images_per_score_sequence + 1:trialIter, :)));
data.correct(trialIter, 1) = ...
data.response(trialIter) == data.truth(trialIter);
if data.correct(trialIter)
score = score + 1;
end
else
data.choicePresentationStart(trialIter, 1) = NaN(1);
data.reactionTime(trialIter, 1) = NaN(1);
Expand All @@ -301,22 +313,20 @@
end

% block done?
if(mod(trialIter, exp_params.images_per_sequence * ...
exp_params.sequences_per_block) == 0)
if(mod(trialIter, imagesPerBlock) == 0)
Screen('DrawTexture', window, backgroundScreen);
Screen('flip', window);
sendTriggers(triggerDevice, exp_params.num_triggers_interrupt, ...
exp_params.trigger_duration, exp_params.trigger_interval);
if exp_params.eyelink
eyelink('message', sprintf('BACKGROUND_%d OFF', trialIter));
Eyelink('message', sprintf('BACKGROUND_%d OFF', trialIter));
end

fprintf('Saving data to %s...\n', sessionFile);
save(sessionFile, 'data', '-append');

performance = score / (exp_params.images_per_sequence * ...
exp_params.sequences_per_block);
score = 0;
performance = data.correct(trialIter - imagesPerBlock + 1:...
trialIter) / imagesPerBlock;
drawScoreScreen(window, blockIndex, performance, ...
exp_params.performanceMessages, black);
WaitForKey(keyboards, 0, exp_params.exit_keys);
Expand All @@ -330,7 +340,7 @@
'center', 'center', black);
Screen('flip', window);
WaitSecs(1);

WaitForKey(keyboards, 0, exp_params.exit_keys);
end
end
Expand All @@ -341,7 +351,7 @@
% save last eyelink file name (if recalibration occured)
eyelinkFile = exp_params.eyelink_file;
if exp_params.eyelink
eyelink('message', 'EXPERIMENT_END');
Eyelink('message', 'EXPERIMENT_END');
end

% show goodbye screen
Expand Down Expand Up @@ -438,18 +448,18 @@
end

function deviceIndex = initializeTrigger()
% initialize PMD1208FS
device=initPMD1208FS;
if isnumeric(device) && device<0
error('Trigger device not found');
else
device=device.index;
err=DaqDConfigPort(device,0,0); % port = 0 direction = 0
FastDaqDout=inline('PsychHID(''SetReport'', device, 2, hex2dec(''04''), uint8([0 port data]))','device', 'port', 'data');
end
deviceIndex = DaqDeviceIndex;
DaqDConfigPort(deviceIndex,0,0);
DaqDOut(deviceIndex,0,0);
% initialize PMD1208FS
device=initPMD1208FS;
if isnumeric(device) && device<0
error('Trigger device not found');
else
device=device.index;
err=DaqDConfigPort(device,0,0); % port = 0 direction = 0
FastDaqDout=inline('PsychHID(''SetReport'', device, 2, hex2dec(''04''), uint8([0 port data]))','device', 'port', 'data');
end
deviceIndex = DaqDeviceIndex;
DaqDConfigPort(deviceIndex,0,0);
DaqDOut(deviceIndex,0,0);
end

function sendTriggers(deviceIndex, numTriggers, ...
Expand Down
Loading

0 comments on commit db10895

Please sign in to comment.