diff sched/rsched.m @ 2:7357e1dc2ad6

Simplified scheduler library with new schedule representation.
author samer
date Sat, 22 Dec 2012 16:17:51 +0000
parents 672052bd81f8
children 0ce3c2070089
line wrap: on
line diff
--- a/sched/rsched.m	Wed Dec 19 22:46:05 2012 +0000
+++ b/sched/rsched.m	Sat Dec 22 16:17:51 2012 +0000
@@ -1,19 +1,10 @@
-function api=rsched(a,S0,dt,T0,varargin)
-% rsched - Schedule regular events with state using timer
+% rsched - regular state threading scheduler
 %
 % rsched ::
-%    (  S       ~'state'
-%       nonneg  ~'current period',
-%       double  ~'scheduled time',
-%       datenum ~'actual time'
-%    -> action (
-%          S      ~'the next event', 
-%          double ~'execution time of current event'
-%       )
-%    )      ~'state transformer',
+%    timed_action({nonneg,S},{S}) ~'timed action from current period and state to state',
 %    S      ~'first state',
-%    double ~'timer period',
-%    double ~'start time',
+%    nonneg ~'timer period',
+%    time   ~'start time',
 %    options {
 %       its     :: natural/inf ~'iteration limit';
 %       defer   :: bool/0 ~ 'if true, do not start timer';
@@ -24,37 +15,38 @@
 %             S       ~'current state', 
 %             real    ~'scheduled start time'
 %             datenum ~'actual time'
-%          -> action unit)/@nop ~ 'called on timer start';
+%          => void)/@nop ~ 'called on timer start';
 %
 %       onstop  :: (
 %             S       ~'current state',
-%             datenum ~'actual time'
-%          -> action unit)/@nop ~ 'called on timer stop';
+%             datenum ~'actual time' %          => void)/@nop ~ 'called on timer stop';
 %
 %       onfinish:: (
 %             S       ~'final state', 
 %             datanum ~'actual time'
-%          -> action unit)/@nop ~ 'called if state seq finishes';
+%          => void)/@nop ~ 'called if state seq finishes';
 %
 %       busy_mode :: {'queue','drop'};
 %       exec_mode :: {'fixedRate','fixedDelay','fixedSpacing'}
 %    }
-% -> action struct {
+% => struct {
 %       timer    :: timer ~'timer being used';
-%       startat  :: (double -> action unit)  ~'start timer at given time';
-%       start    :: (unit   -> action unit)  ~'start timer asap';
-%       stop     :: (unit   -> action unit)  ~'stop timer';
-%       rewind   :: (unit   -> action unit)  ~'rewind to first state';
-%       trim     :: (double -> action double)~'trim timing errors';
-%       dispose  :: (unit   -> action unit)  ~'stop timer';
-%       getstate :: (unit   -> action S)     ~'current state';
-%       setstate :: (S      -> action unit)  ~'set state (only when stopped)';
-%       isrunning:: (unit   -> action bool)  ~'true if scheduler is running'
+%       startat  :: (double => void)  ~'start timer at given time';
+%       start    :: (void   => void)  ~'start timer asap';
+%       stop     :: (void   => void)  ~'stop timer';
+%       rewind   :: (void   => void)  ~'rewind to first state';
+%       trim     :: (double => double)~'trim timing errors';
+%       dispose  :: (void   => void)  ~'stop timer';
+%       getstate :: (void   => S)     ~'current state';
+%       setstate :: (S      => void)  ~'set state (only when stopped)';
+%       isrunning:: (void   => bool)  ~'true if scheduler is running';
+%       wait     :: (void   => void)  ~'wait for sched to stop'
 %    }.
 %
 % NB: switching on final state availability option 'final' can make
 % timer callbacks much slower due to requirement for copying state.
 
+function api=rsched(schedfn,S0,dt,T0,varargin)
 
 	warning('off','MATLAB:TIMER:STARTDELAYPRECISION');
 	warning('off','MATLAB:TIMER:RATEPRECISION');
@@ -65,7 +57,7 @@
 
 	% Implementation note: it's MUCH faster to use a local variable
 	% as mutable state instead of using the timer getter and setter.
-	State={T0,S0}; 
+	State=S0; SchedStart=T0; FinalState=[];
 	STARTERR=getparam(opts,'error',0); 
 	DT=dt;
 
@@ -85,22 +77,23 @@
 		'setstate',	@setstate, ...
 		'trim',   	@trim, ...
 		'timer',    @()Timer ...
+		'wait',     @sched_wait
 	);
 	
-	if opts.final, api.finalstate=@()State{1}; end
+	if opts.final, api.finalstate=@()FinalState; end
 	if ~opts.defer, startat(T0); end
 
 	function check(msg), if isrunning(Timer), error(msg); end; end
 	function err=trim(derr), STARTERR=STARTERR+derr; err=STARTERR; end
-	function s=getstate, s=State{2}; end
+	function s=getstate, s=State; end
 	function setstate(s), 
 		check('Cannot set state of running scheduler'); 
-		State{2}=s; 
+		State=s; 
 	end
 
 	function startat(t0) % !! what if timer is already running?
 		check('Timer is already running');
-		State{1}=t0;
+		SchedStart=t0;
 		start_delay = t0-nows-STARTERR
 		if start_delay<0
 			fprintf('\n| WARNING: start delay=%f, starting now.',start_delay);
@@ -112,50 +105,38 @@
 
 	function startnow % !! what if timer is already running?
 		check('Timer is already running');
-		State{1}=nows+STARTERR;
+		SchedStart=nows+STARTERR;
 		set(Timer,'StartDelay',0);
 		start(Timer);
 	end
 
 	function stopfn(o,e), 
-		opts.onstop(State{2},e.Data.time); 
-		if isempty(State{2}), 
-			opts.onfinish(State{1},e.Data.time); 
+		opts.onstop(State,e.Data.time); 
+		if isempty(State), 
+			opts.onfinish(State,e.Data.time); 
 		end
 	end
 
 	function startfn(o,e)
 		DT=get(o,'Period'); % use current period in timer callback
-		opts.onstart(State{2},State{1},e.Data.time); 
+		opts.onstart(State,SchedStart,e.Data.time); 
 	end
 
 	% if final state not required we can use faster assign in place
 	function adv2(o,e)
-		t0=State{1};
-		[State{2},tt]=a(State{2},DT,t0,e.Data.time);
-		% could accumulate stats about tt-t0 here
-
-		if isempty(State{2}), 
-			State{1}=[]; 
-			stop(o);
-		else
-			State{1}=t0+DT;
-		end
+		[err,State]=schedfn(SchedStart,DT,State);
+		if isempty(State), stop(o); end
+		SchedStart=SchedStart+DT;
 	end
 
 	% final state required
 	function adv(o,e)
-		[t0,s0]=State{:};
-		[s1,tt]=a(s0,DT,t0,e.Data.time);
-		% could accumulate stats about tt-t0 here
+		[err,s1]=schedfn(SchedStart,DT,State);
+		if isempty(s1), FinalState=State; stop(o); end
+		SchedStart=SchedStart+DT;
+		State=s1;
+	end
 
-		if isempty(s1), 
-			State{1}=s0;
-			State{2}=[];
-			stop(o);
-		else
-			State{1}=t0+DT;
-			State{2}=s1;
-		end
+	function sched_wait
+		while Timer.isrunning(); pause(0.05); end
 	end
-end