Prevent unwanted timer callback calls in the execution queue

5 views (last 30 days)
Hi, I made a GUI in guide with the following purpose: A random number appears in one of two boxes on the screen and the user is supposed to press either left or right on the keyboard depending on whether the number is even or odd. This is done through a windowkeypressfcn that only reacts to these two button presses apart from 'return' to start and 'escape' to end the session. After a key has been pressed the boxes are cleared and another number appears after 0.5-2s - chosen randomly using the pause() function. If the user fails to respond within 2.5 s the timer callback gets called, the boxes cleared and another number appears after 0.5-2s again. I am basically tracking their response times (using tic and toc) and in case the timer callback gets called I know they are being too slow. The important thing is that the user sees the number in one of the boxes changing every time one of the 2 functions is called! Ok, I create a timer object the following way
handles.timer = timer('ExecutionMode','fixedSpacing','BusyMode','drop','StartDelay',2.5,'Period',2.5,'TimerFcn', {@update_boxes,hObject});
The timer gets stopped every time the gui enters the button press callback function and started again when it exits the function. Same goes for the timer callback. The GUI works fine apart from one (very unlikely but still) scenario: If the user completely goofs off and doesn't press anything for a while, the timer function at some point (usually after it has been called twice or three times consecutively - so in the twice case the user hasn't reacted for 5s+ x1+x2, where x1 and x2 are random numbers from the interval 0.5-2s )gets executed twice in such a way that the user only sees one number change even though 2 occurred. I save all the numbers that were presented and in this case there are more numbers in the output vector than I have actually seen. I would assume that it has something to do with the examples presented here: http://www.mathworks.nl/help/matlab/matlab_prog/handling-timer-queuing-conflicts.html.
I assume that the timer callback execution gets queued up (whatever I set for the 'BusyMode' parameter, at least one instance will be in the queue..) and called at some point when the random 0.5-2s pauses add up. How can I fix this? Is there a way not to put the timer callback execution in the queue but delete it? I thought about creating and deleting a new timer object each time but I can't do that since I'm in the timer callback function and it also doesn't seem like an elegant solution...
Sorry for the long post... Here's the code in case it helps:
%%%% Key press fcn
function figure1_WindowKeyPressFcn(hObject, eventdata, handles)
if handles.firstiteration==0 %if it's not the first iteration save the responses
% check whether keystorke occured while boxes were blank, if so
% disregard it
if ~(strcmp(get(handles.eo_numberl,'String'),'')&& strcmp(get(handles.eo_numberr,'String'),''))
switch eventdata.Key
case 'leftarrow'
% get the reaction time and save it
timing_var=toc;
handles.responsetimes = [handles.responsetimes,timing_var];
% stop timer and evaluate
if strcmp(get(handles.timer, 'Running'), 'on')
stop(handles.timer);
end
set(handles.eo_numberl, 'string', '');
set(handles.eo_numberr, 'string', '');
pause_dur = 0.5 + (2-0.5).*rand(1);% pause between 0.5 and 2s
pause(pause_dur);
% compare number and response and save both
handles.responses = [handles.responses,1];
handles.rand_numbers = [handles.rand_numbers,handles.number];
handles.number = randi(8,1,1);% generate random number
% choose window to show number in
choose_window = round(rand(1));
if choose_window == 0
set(handles.eo_numberl, 'string', num2str(handles.number));
set(handles.eo_numberr, 'string', '');
elseif choose_window == 1;
set(handles.eo_numberr, 'string', num2str(handles.number));
set(handles.eo_numberl, 'string', '');
end
tic
case 'rightarrow'
% get the reaction time and save it
timing_var=toc;
handles.responsetimes = [handles.responsetimes,timing_var];
% stop timer and evaluate
if strcmp(get(handles.timer, 'Running'), 'on')
stop(handles.timer);
end
% get the reaction time and save it
set(handles.eo_numberl, 'string', '');
set(handles.eo_numberr, 'string', '');
pause_dur = 0.5 + (2-0.5).*rand(1);% pause between 0.5 and 2s
pause(pause_dur);
% compare number and response and save both
handles.responses = [handles.responses,0];
handles.rand_numbers = [handles.rand_numbers,handles.number];
handles.number = randi(8,1,1);% generate random number
% choose window to show number in
choose_window = round(rand(1));
if choose_window == 0
set(handles.eo_numberl, 'string', num2str(handles.number));
set(handles.eo_numberr, 'string', '');
elseif choose_window == 1;
set(handles.eo_numberr, 'string', num2str(handles.number));
set(handles.eo_numberl, 'string', '');
end
tic;
case('escape')
figure1_CloseRequestFcn(hObject, eventdata, handles);
return;
otherwise
return;
end
% start timer again
% Only start timer if it is not running
if strcmp(get(handles.timer, 'Running'), 'off')
start(handles.timer);
end
% if it takes more than 2.5s to press a button move on to the
% next number
end
else
% start with enter
if strcmp(eventdata.Key,'return')
set(handles.startexp, 'visible','off');
set(handles.text2, 'visible', 'on');
set(handles.eo_numberr, 'visible','on');
set(handles.eo_numberl, 'visible','on');
% if it's the first keystroke, don't take reaction time into account
disp('************************************************************************************');
% pause_dur = 0.5 + (2-0.5).*rand(1);% pause between 0.5 and 2s
pause_dur = 2.5;
pause(pause_dur);
% start the playback
play(handles.player);
handles.firstiteration =0;
handles.number = randi(8,1,1);% generate random number
% choose window to show number in
choose_window = round(rand(1));
if choose_window == 0
set(handles.eo_numberl, 'string', num2str(handles.number));
set(handles.eo_numberr, 'string', '');
elseif choose_window == 1;
set(handles.eo_numberr, 'string', num2str(handles.number));
set(handles.eo_numberl, 'string', '');
end
% start timer again
start(handles.timer);
tic;
% if it takes more than 2.5s to press a button move on to the
% next number
elseif strcmp(eventdata.Key,'escape')
figure1_CloseRequestFcn(hObject, eventdata, handles);
return;
end
end
guidata(hObject, handles);
%%% Timer callback
function update_boxes(hObject,eventdata,hfigure)
handles = guidata(hfigure);
if strcmp(get(handles.timer, 'Running'), 'on')
%%%%%%this part is wrong
stop(handles.timer);
end
if ~(strcmp(get(handles.eo_numberl, 'String'),'') && strcmp(get(handles.eo_numberr, 'String'),''))&& (handles.timerfcnflag == 0)
handles.timerfcnflag = 1;
handles.timerfcnflag
disp('timerfcn');
% timing_var=toc;
% save invalid reaction time
handles.responsetimes = [handles.responsetimes,-1];
set(handles.eo_numberl, 'string', '');
set(handles.eo_numberr, 'string', '');
pause_dur = 0.5 + (2-0.5).*rand(1);% pause between 0.5 and 2s
pause(pause_dur);
handles.responses = [handles.responses,2];
handles.rand_numbers = [handles.rand_numbers,handles.number];
choose_window = round(rand(1));
handles.number = randi(8,1,1);% generate random number
if choose_window == 0
set(handles.eo_numberl, 'string', num2str(handles.number));
set(handles.eo_numberr, 'string', '');
% start measuring responsetime again
tic;
elseif choose_window == 1;
set(handles.eo_numberr, 'string', num2str(handles.number));
set(handles.eo_numberl, 'string', '');
% start measuring responsetime again
tic;
end
% start timer again
% Only start timer if it is not running
if strcmp(get(handles.timer, 'Running'), 'off')
%%%%%%this part is wrong
start(handles.timer);
end
handles.timerfcnflag = 0;
handles.timerfcnflag
end
% if it takes more than 2.5s to press a button move on to the
% next number etc
guidata(hfigure, handles);
  3 Comments
Nemanja
Nemanja on 8 Mar 2014
Hi Jan, sorry I'm not sure how to describe it... Ok, so what I want is for the timer to start running when the gui starts, stop if a button is pressed within 2.5 s and start again at the end of the buttonpress callback and wait for input again and repeat until the gui is closed. If the button is not pressed in 2.5s, I want to call the timer callback, and start the timer again at the end of it, wait for input and repeat until the gui is closed. So the timer callback should only be called if in an iteration the input takes more than 2.5s. However, if I just open the gui and wait, so press nothing, the timer callback gets called more often than it should - so not every 2.5s (+ whatever delay is caused by the callback execution) but 2 consecutive calls occur every now and then. I don't know why this is and how to fix it. Hope this clears it up a bit...
Nemanja
Nemanja on 8 Mar 2014
I figured it out... I was stopping the timer whenever the timer callback is entered and starting it again before it is left. Since I set the period to 2.5s and busymode to 'fixedSpacing' this was unnecessary and messed things up. It's working now and that's good but I'd still like to understand what actually goes wrong when you call the stop and start within the timer callback.

Sign in to comment.

Answers (0)

Categories

Find more on Interactive Control and Callbacks in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!