Mercurial > hg > ishara
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