function Timer=ssched(ee)
% ssched - Schedule events using timer with state threading through event calls
%
% ssched ::
%    cell {
%       (  S      ~'state'
%          double ~'scheduled time',
%          double ~'actual time'
%       -> S      ~'next state',
%          double ~'next execution time',
%          double ~'actual execution time'
%       ),
%       double ~'time of first event',
%       S      ~'initial state'
%    }
% -> action timer ~'timer being used'.
%
% Semantics:
%
% Because subsequent events are dependent on the return values from previous
% events, we must call each event action even if we know it is late. It is up
% the actions themselves to decide what to do if they are late.

	persistent ERROR
	ERROR=[];
	
	warning('off','MATLAB:TIMER:STARTDELAYPRECISION');

	[a,t0,s0]=cdeal(ee);

	Timer=timer;
	set(Timer,'UserData',{t0,s0});
	set(Timer,'TimerFcn',@timercb,'StopFcn',@chain);
	set(Timer,'StartDelay',max(0,t0-nows)); % there will be some small error here..
	start(Timer);

	function timercb(o,e)
		[t0,s0]=cdeal(get(o,'UserData'));
		[s1,t1,tt]=a(s0,t0,e.Data.time);
		set(o,'UserData',{t1,s1});
		ERROR=vertcat(ERROR,tt-t0);
	end

	function chain(o,e)
		[t1,s1]=cdeal(get(o,'UserData'));
		correction=mean(ERROR);
		while ~isempty(t1)
			tnow=nows;
			delay=t1-correction-tnow;
			if delay>=0, 
				set(o,'StartDelay',delay); 
				start(o);
				return; 
			end
			[s1,t1,tt]=a(s1,t1,tnow);
		end

		fprintf('\n| stopping\n');
		set(o,'UserData',ERROR);
		delete(o);
	end
end
