function PeekBlankingTest
% PeekBlankingTest analyzes the recorded times of all the blanking
% interrupts. It plots the duration of every interval recorded over
% several seconds. Ideally all the intervals would be identical.
% 
% Depending on Screen Preference settings and processor priority,
% WaitBlanking relies on either the blanking interrupt or SetClut to synch
% to the display. See "Screen WaitBlanking?".
% 
% See also RushTest, WaitBlankingTest, FlickerTest, SetClutTest, and ScreenTest.

% 2/17/02 dgp test all screens at several priority levels.
% 2/18/02 dgp Report whether WaitBlanking uses interrupt or SetClut.
% 2/18/02 dgp Cosmetic.
% 2/18/02 dgp Add range.
% 2/19/02 dgp Close old figures.
% 2/20/02 dgp Test all priorities in both modes.
% 2/21/02 dgp Override SetClutDriverWaitsForBlanking.
% 2/24/02 dgp Run for 3 secs, even if WaitBlanking doesn't wait.
% 3/25/02 dgp Print the "too fast" note only once.
% 4/24/02 awi Exit on PC with message.

if strcmp('PCWIN',computer)
    error('Win: PeekBlankingTest not yet supported.');
end


close all; % figures
fprintf('PeekBlankingTest\n');
fprintf('Times a loop that calls Screen WaitBlanking, reports the iteration rate\n');
fprintf('in Hz, and graphs the interval duration. \n');
for whichScreen=Screen('Screens');
	DescribeScreen(whichScreen);
	DescribeScreenPrefs(whichScreen);
	DescribeScreen(-2);
	fprintf('WaitBlanking is using blanking interrupt:\n');
	Screen(whichScreen,'Preference','WaitBlankingAlwaysCallsSetClut',0);
	pmax=MaxPriority(whichScreen,'GetSecs','WaitBlanking','BlankingInterrupt');
	Test(whichScreen,pmax);
	DescribeScreen(-2);
	fprintf('WaitBlanking is using SetClut:\n');
	Screen(whichScreen,'Preference','WaitBlankingAlwaysCallsSetClut',1);
	pmax=MaxPriority(whichScreen,'GetSecs','WaitBlanking');
	Test(whichScreen,pmax);
end
DescribeScreen(-1);

function Test(whichScreen,pmax)
setClutDriverWaitsForBlanking=Screen(whichScreen,'Preference','SetClutDriverWaitsForBlanking');
if ~setClutDriverWaitsForBlanking & Screen(whichScreen,'Preference','WaitBlankingAlwaysCallsSetClut')
	fprintf('NOTE: SetClutDriverWaitsForBlanking was zero, so this test will probably run too fast.\n');
end
for p=[0 0.5 1 2 7]
	if p>pmax
		break
	end

	setClutDriverWaitsForBlanking=Screen(whichScreen,'Preference','SetClutDriverWaitsForBlanking',1);
	if ~Screen(whichScreen,'Preference','WaitBlankingAlwaysCallsSetClut') & p<=MaxPriority(whichScreen,'BlankingInterrupt')
		method='using interrupt';
	else
		method='using setclut';
	end

	n=round(2.5*FrameRate(whichScreen)); % 2.5 seconds' worth
	clear t;
	t=zeros(1000*n,1); % Allocate enough to cope with not waiting, e.g. 10000 Hz iteration of loop.
	i=1;frame=0;stop=0;
	loop={
		'i=1;'
		'stop=GetSecs+3;'
		'while GetSecs<stop;'
			'Screen(whichScreen,''WaitBlanking'');'
			'[frame,t(i)]=Screen(whichScreen,''PeekBlanking'');'
			'i=i+1;'
		'end;'
		'n=i-1;'
	};
	
 	Rush(loop,p)
	Screen(whichScreen,'Preference','SetClutDriverWaitsForBlanking',setClutDriverWaitsForBlanking);

	dt=diff(t(3:n)); % discard the first few intervals, for no good reason.
	clear t;
	t=cumsum(dt);
	dt=1000*dt;
	dev=[min(dt) max(dt)]-mean(dt);
	sds=sprintf('standard deviation %.0f µs, range %.0f, %.0f µs',1000*std(dt),1000*dev);	
	condition=sprintf('priority %g, %s, %.0f Hz',p,method,1000/mean(dt));
	fprintf('priority %3g, %3.0f Hz, %s\n',p,1000/mean(dt),sds);

	% plot duration over time
	figure;
	plot(t-t(1),dt)
	title(sprintf('Screen %d. Variation in duration (of interval between blanking interrupts) over time',whichScreen))
	xlabel('Time (s)');
	ylabel('Duration (ms)');
	text(1,1,sds,'Units','characters');
	text(1,2,condition,'Units','characters');
	figure(gcf)
	drawnow
end
