-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathBitsi.m
261 lines (225 loc) · 8.98 KB
/
Bitsi.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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
%
% %Constructor%
%
% Bitsi(comport)
%
% When creating a new 'bitsi' object, you can specify to which comport it
% is connected. On windows computers, this is usually something like
% 'com1'.
% When using an empty string for 'comport', the object will run in testing
% mode. In this case it's not required to have the BITSI physically
% connected to the computer. Responses will be read from the keyboard.
%
% *Methods*
% - sendTrigger(code)
% - getResponse(timeout, return_after_response)
% - clearResponses()
% - numberOfResponses()
% - close()
%
%
%
% *sendTrigger(code)*
% code - trigger code, allowed codes 1 - 255. This code is sent to the
% BITSI which will output it on it's parallel output port. The code will be
% reset after 10 miliseconds.
%
% * [response time] = getResponse(timeout, return_after_response)*
%
% This function will take maximally 'timeout' seconds to execute
% return_after_response - allowed values: true or false
%
% False:
% If return_after_response equals false, getResponse will wait for a fixed
% duration (timeout) and record the first response during the wait. The
% first response and it's timeout will be returned after the specified
% timeout.
%
% < timeout >
% +-----------------+
% | A |
% --+ | +----------------
%
%
%
% True:
% This method will return as soon as there is a response. Both
% the response and the timestamp of the response will be returned.
% If 'timeout' seconds have been expired without a response, a response
% of 0 will be returned.
%
% < timeout >
% +-----------+
% | A|
% --+ |+----------------
%
%
%
% *Example*
%
% b = Bitsi('com1');
%
% b.sendTrigger(20);
%
% ... do more stuff here
%
% [r t] = b.getResponse(10, false);
%
% b.close();
%
%
% If the constructor is called with an empty com port string, no serial connection will be
% established. The serial commands will be echo'd to stdout:
%
% b = Bitsi('')
% ...
%
%
classdef Bitsi
properties (SetAccess = public)
serobj;
debugmode = false;
end
methods
function B = Bitsi(comport)
if (strcmp(comport, ''))
fprintf('Bitsi: No Com port given, running in testing mode...\n')
B.debugmode = true;
KbName('UnifyKeyNames');
end
if (not(B.debugmode))
%delete(instrfind);
B.serobj = serial(comport);
% serial port configuration
set(B.serobj, 'Baudrate', 115200);
set(B.serobj, 'Parity', 'none');
set(B.serobj, 'Databits', 8); % number of data bits
set(B.serobj, 'StopBits', 1); % number of stop bits
%set(B.serobj, 'Terminator', 'CR/LF'); % line ending character
% see also:
% http://www.mathworks.com/matlabcentral/newsreader/view_original/292759
%set(B.serobj, 'InputBufferSize', 1); % set read buffBuffer for read
set(B.serobj, 'FlowControl', 'none'); %
% open the serial port
fopen(B.serobj);
% since matlab pulls the DTR line, the arduino will reset
% so we have to wait for the initialization of the controller
oldState = pause('query');
pause on;
pause(2.5);
pause(oldState);
% read all bytes available at the serial port
status = '[nothing]';
if B.serobj.BytesAvailable > 0
status = fread(B.serobj, B.serobj.BytesAvailable);
end
fprintf('Bitsi says: %s', char(status));
fprintf('\n');
end
end
function sendTrigger(B,code)
% checking code range
if code > 255
fprintf('Bitsi: Error, code should not exeed 255\n');
return;
end
if code < 1
fprintf('Bitsi: Error, code should be bigger than 0\n');
return;
end
% fprintf('Bitsi: trigger code %f\n', code);
if ~B.debugmode
fwrite(B.serobj, code)
end
end
function x = numberOfResponses(B)
if (~B.debugmode)
x = B.serobj.BytesAvailable;
else
x = 0; % assume that in debugging no more responses left
end
end
function clearResponses(B)
if (~B.debugmode)
numberOfBytes = B.serobj.BytesAvailable;
if numberOfBytes > 0
fread(B.serobj, numberOfBytes);
end
end
end
function [response, timestamp]= getResponse(B,wait_time, return_after_response)
response = 0;
% start stopwatch
timeout = GetSecs + wait_time;
if (B.debugmode)
while GetSecs < timeout && ( ~return_after_response || response ==0)
% poll the state of the keyboard
[keyisdown, when, keyCode] = KbCheck;
% if there wasn't a response before and there is a
% keyboard press available
if response == 0 && keyisdown
timestamp = when;
response = find(keyCode);
% make sure to return just one keyCode
% but first dump it to console
if length(response) > 1
fprintf('Bitsi::getResponse() - More than one button pressed: ');
disp(response);
response = response(1);
end
KbWait([],1); % wait explicitly for key to be released
%added by Diego Lozano 26-May-2012 09:50:45
B.sendTrigger(response);
if return_after_response
break;
end
end
WaitSecs(0.001); % to avoid overloading system
end
% if no response yet after timeout
if (response == 0)
timestamp = GetSecs;
end
else % listening to actual Bitsi-box
% depending on 'return_after_response' this loop will run
% for timeout seconds or until a response is given
while GetSecs < timeout && ( ~return_after_response || response == 0)
% if there wasn't a response before and there is a
% serial character available
if response == 0 && B.serobj.BytesAvailable > 0
% capture the time and the response
timestamp = GetSecs;
response = fread(B.serobj, 1);
%added by Diego Lozano 26-May-2012 09:50:45
B.sendTrigger(response);
fprintf('Bitsi: response code %i\n', response); %prints response to command line - JvB
end
end
% if no response yet after timeout
if (response == 0)
timestamp = GetSecs;
end
% In some other versions of Bitsi.m there is a
% clearResponses call here, I think this can get you into
% trouble in certain cases. Just make sure you call
% clearResponses yourself when needed.
% == Notes added by Jeroen van Baar on 20-Mar-2015 11:40 ==
% Note that fread takes the response out of the buffer. This can have unintuitive effects.
% Suppose your participant presses a button and releases it straight away. Two responses are
% added to the buffer: button_down and button_up. getResponse() calls fread which takes the
% first response out of the buffer: button_down. Button_up is still in there! So the next time
% you call getResponse(), it will immediately return with button_up. This is why it is necessary
% to call clearResponses() at strategic times. Also, remember that you can't get a response back
% once it's out of the buffer, unless you store it in a variable (as happens up here: the
% response is stored in the variable 'response').
end
end
% close
function close(B)
if (not(B.debugmode))
fclose(B.serobj);
delete(B.serobj);
end
end
end % methods
end % classdef