-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathwaitForTrigger.m
193 lines (157 loc) · 5.65 KB
/
waitForTrigger.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
function [lastTriggerTimeStamp] = waitForTrigger(varargin)
%
% Counts a certain number of triggers coming from the scanner before returning.
%
% USAGE:
%
% [lastTriggerTimeStamp] = waitForTrigger([cfg,] ...
% [deviceNumber,] ...
% [quietMode,] ...
% [nbTriggersToWait])
%
% :param cfg:
% :type cfg: struct
% :param deviceNumber: device number of the keyboard or trigger box in MRI
% :type deviceNumber: integer
% :param quietMode: a boolean to make sure nothing is printed on the screen or the prompt
% :type quietMode: boolean
% :param nbTriggersToWait: number of triggers to wait
% :type nbTriggersToWait: integer
%
% :returns:
%
% - :lastTriggerTimeStamp: (optional) it can be used as experimentStart
% timestamp (``cfg.experimentStart``)
%
% If you are not using the quietMode, it flips and waits for half a TR before starting to
% check for the next trigger (unless this was the last trigger to wait for and in
% this case it returns immediately).
%
% Will print the count down in the command line and on the PTB window if one is
% opened.
%
% If the fMRI sequence RT is provided (``cgf.MRI.repetitionTime``) then it will wait
% for half a RT before starting to check for next trigger, otherwise it will
% wait 500 ms.
%
% When no deviceNumber is set then it will check the default device: this is
% probably only useful in debug as you will want to make sure you get the
% triggers coming from the scanner in a real case scenario.
%
% (C) Copyright 2020 CPP_PTB developers
[cfg, nbTriggersToWait, deviceNumber, quietMode] = checkInputs(varargin);
triggerCounter = 0;
if strcmpi(cfg.testingDevice, 'mri')
msg = ['Experiment starting in ', ...
num2str(nbTriggersToWait - triggerCounter), '...'];
talkToMe(cfg, msg, quietMode);
while triggerCounter < nbTriggersToWait
keyCode = []; %#ok<NASGU>
[~, lastTriggerTimeStamp, keyCode] = KbCheck(deviceNumber);
if strcmp(KbName(keyCode), cfg.mri.triggerKey)
triggerCounter = triggerCounter + 1;
msg = sprintf(' Trigger %i', triggerCounter);
talkToMe(cfg, msg, quietMode);
% we only wait if this is not the last trigger
if triggerCounter < nbTriggersToWait
pauseBetweenTriggers(cfg);
end
end
end
end
end
function [cfg, nbTriggersToWait, deviceNumber, quietMode] = checkInputs(varargin)
varargin = varargin{1};
if numel(varargin) < 1 || isempty(varargin{1}) || ~isstruct(varargin{1})
error('First input must be a cfg structure.');
elseif isstruct(varargin{1})
cfg = varargin{1};
end
if numel(varargin) < 3 || isempty(varargin{3})
quietMode = false;
else
quietMode = varargin{3};
end
if numel(varargin) < 2 || isempty(varargin{2})
deviceNumber = -1;
if ~quietMode
fprintf('Will wait for triggers on the main keyboard device.\n');
end
else
deviceNumber = varargin{2};
end
if numel(varargin) < 4 || isempty(varargin{4})
nbTriggersToWait = cfg.mri.triggerNb;
else
nbTriggersToWait = varargin{4};
end
end
function talkToMe(cfg, msg, quietMode)
if ~quietMode
fprintf([msg, ' \n']);
if isfield(cfg, 'screen') && isfield(cfg.screen, 'win')
DrawFormattedText(cfg.screen.win, msg, ...
'center', 'center', cfg.text.color);
Screen('Flip', cfg.screen.win);
end
end
end
function pauseBetweenTriggers(cfg)
% we pause between triggers otherwise KbWait and KbPressWait might be too fast and could
% catch several triggers in one go.
waitTime = 0.5;
if isfield(cfg, 'mri') && isfield(cfg.mri, 'repetitionTime') && ~isempty(cfg.mri.repetitionTime)
waitTime = cfg.mri.repetitionTime / 2;
end
WaitSecs(waitTime);
end
% function [MyPort] = WaitForScanTrigger(Parameters)
%
% %% Opening IOPort
% PortSettings = sprintf('BaudRate=115200 InputBufferSize=10000 ReceiveTimeout=60');
% PortSpec = FindSerialPort([], 1);
%
% % Open port portSpec with portSettings, return handle:
% MyPort = IOPort('OpenSerialPort', PortSpec, PortSettings);
%
% % Start asynchronous background data collection and timestamping. Use
% % blocking mode for reading data -- easier on the system:
% AsyncSetup = sprintf('BlockingBackgroundRead=1 ReadFilterFlags=0 StartBackgroundRead=1');
% IOPort('ConfigureSerialPort', MyPort, AsyncSetup);
%
% % Read once to warm up
% WaitSecs(1);
% IOPort('Read', MyPort);
%
% nTrig = 0;
%
% %% waiting for dummie triggers from the scanner
% while nTrig <= Parameters.Dummies
%
% [PktData, TReceived] = IOPort('Read', MyPort);
%
% % it is checked if something was received via trigger_port
% % oldtrigger is there so 'number' is only updated when something new is
% % received via trigger_port (normally you receive a "small series" of data at
% % a time)
% if isempty(PktData)
% TReceived = 0;
% end
%
% if TReceived && (oldtrigger == 0)
% Number = 1;
% else
% Number = 0;
% end
%
% oldtrigger = TReceived;
%
% if Number
% nTrig = nTrig + 1;
% Number = 0; %#ok<NASGU>
% end
%
% end
%
% end
%