annotate 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
rev   line source
samer@2 1 % rsched - regular state threading scheduler
samer@0 2 %
samer@0 3 % rsched ::
samer@2 4 % timed_action({nonneg,S},{S}) ~'timed action from current period and state to state',
samer@0 5 % S ~'first state',
samer@2 6 % nonneg ~'timer period',
samer@2 7 % time ~'start time',
samer@0 8 % options {
samer@0 9 % its :: natural/inf ~'iteration limit';
samer@0 10 % defer :: bool/0 ~ 'if true, do not start timer';
samer@0 11 % error :: real/0 ~ 'estimate of timing error on timer start';
samer@0 12 % final :: bool/0 ~ 'make final state available?';
samer@0 13 %
samer@0 14 % onstart :: (
samer@0 15 % S ~'current state',
samer@0 16 % real ~'scheduled start time'
samer@0 17 % datenum ~'actual time'
samer@2 18 % => void)/@nop ~ 'called on timer start';
samer@0 19 %
samer@0 20 % onstop :: (
samer@0 21 % S ~'current state',
samer@2 22 % datenum ~'actual time' % => void)/@nop ~ 'called on timer stop';
samer@0 23 %
samer@0 24 % onfinish:: (
samer@0 25 % S ~'final state',
samer@0 26 % datanum ~'actual time'
samer@2 27 % => void)/@nop ~ 'called if state seq finishes';
samer@0 28 %
samer@0 29 % busy_mode :: {'queue','drop'};
samer@0 30 % exec_mode :: {'fixedRate','fixedDelay','fixedSpacing'}
samer@0 31 % }
samer@2 32 % => struct {
samer@0 33 % timer :: timer ~'timer being used';
samer@2 34 % startat :: (double => void) ~'start timer at given time';
samer@2 35 % start :: (void => void) ~'start timer asap';
samer@2 36 % stop :: (void => void) ~'stop timer';
samer@2 37 % rewind :: (void => void) ~'rewind to first state';
samer@2 38 % trim :: (double => double)~'trim timing errors';
samer@2 39 % dispose :: (void => void) ~'stop timer';
samer@2 40 % getstate :: (void => S) ~'current state';
samer@2 41 % setstate :: (S => void) ~'set state (only when stopped)';
samer@2 42 % isrunning:: (void => bool) ~'true if scheduler is running';
samer@2 43 % wait :: (void => void) ~'wait for sched to stop'
samer@0 44 % }.
samer@0 45 %
samer@0 46 % NB: switching on final state availability option 'final' can make
samer@0 47 % timer callbacks much slower due to requirement for copying state.
samer@0 48
samer@2 49 function api=rsched(schedfn,S0,dt,T0,varargin)
samer@0 50
samer@0 51 warning('off','MATLAB:TIMER:STARTDELAYPRECISION');
samer@0 52 warning('off','MATLAB:TIMER:RATEPRECISION');
samer@0 53
samer@0 54 opts=prefs('defer',0,'its',inf,'final',0, ...
samer@0 55 'onstart',@nop,'onstop',@nop,'onfinish',@nop, ...
samer@0 56 'busy_mode','queue','exec_mode','fixedRate',varargin{:});
samer@0 57
samer@0 58 % Implementation note: it's MUCH faster to use a local variable
samer@0 59 % as mutable state instead of using the timer getter and setter.
samer@2 60 State=S0; SchedStart=T0; FinalState=[];
samer@0 61 STARTERR=getparam(opts,'error',0);
samer@0 62 DT=dt;
samer@0 63
samer@0 64 if opts.final, timfn=@adv; else timfn=@adv2; end
samer@0 65 Timer=timer('ExecutionMode',opts.exec_mode,'BusyMode',opts.busy_mode, ...
samer@0 66 'StartFcn',@startfn,'StopFcn',@stopfn,'TimerFcn',timfn, ...
samer@0 67 'Period',DT,'TasksToExecute',opts.its);
samer@0 68
samer@0 69 api = struct(...
samer@0 70 'dispose', @()delete(Timer), ...
samer@0 71 'isrunning',@()isrunning(Timer), ...
samer@0 72 'startat', @startat, ...
samer@0 73 'start', @startnow, ...
samer@0 74 'stop', @()stop(Timer), ...
samer@0 75 'rewind', @()setstate(S0), ...
samer@0 76 'getstate', @getstate, ...
samer@0 77 'setstate', @setstate, ...
samer@0 78 'trim', @trim, ...
samer@0 79 'timer', @()Timer ...
samer@2 80 'wait', @sched_wait
samer@0 81 );
samer@0 82
samer@2 83 if opts.final, api.finalstate=@()FinalState; end
samer@0 84 if ~opts.defer, startat(T0); end
samer@0 85
samer@0 86 function check(msg), if isrunning(Timer), error(msg); end; end
samer@0 87 function err=trim(derr), STARTERR=STARTERR+derr; err=STARTERR; end
samer@2 88 function s=getstate, s=State; end
samer@0 89 function setstate(s),
samer@0 90 check('Cannot set state of running scheduler');
samer@2 91 State=s;
samer@0 92 end
samer@0 93
samer@0 94 function startat(t0) % !! what if timer is already running?
samer@0 95 check('Timer is already running');
samer@2 96 SchedStart=t0;
samer@0 97 start_delay = t0-nows-STARTERR
samer@0 98 if start_delay<0
samer@0 99 fprintf('\n| WARNING: start delay=%f, starting now.',start_delay);
samer@0 100 start_delay=0;
samer@0 101 end
samer@0 102 set(Timer,'StartDelay',start_delay);
samer@0 103 start(Timer);
samer@0 104 end
samer@0 105
samer@0 106 function startnow % !! what if timer is already running?
samer@0 107 check('Timer is already running');
samer@2 108 SchedStart=nows+STARTERR;
samer@0 109 set(Timer,'StartDelay',0);
samer@0 110 start(Timer);
samer@0 111 end
samer@0 112
samer@0 113 function stopfn(o,e),
samer@2 114 opts.onstop(State,e.Data.time);
samer@2 115 if isempty(State),
samer@2 116 opts.onfinish(State,e.Data.time);
samer@0 117 end
samer@0 118 end
samer@0 119
samer@0 120 function startfn(o,e)
samer@0 121 DT=get(o,'Period'); % use current period in timer callback
samer@2 122 opts.onstart(State,SchedStart,e.Data.time);
samer@0 123 end
samer@0 124
samer@0 125 % if final state not required we can use faster assign in place
samer@0 126 function adv2(o,e)
samer@2 127 [err,State]=schedfn(SchedStart,DT,State);
samer@2 128 if isempty(State), stop(o); end
samer@2 129 SchedStart=SchedStart+DT;
samer@0 130 end
samer@0 131
samer@0 132 % final state required
samer@0 133 function adv(o,e)
samer@2 134 [err,s1]=schedfn(SchedStart,DT,State);
samer@2 135 if isempty(s1), FinalState=State; stop(o); end
samer@2 136 SchedStart=SchedStart+DT;
samer@2 137 State=s1;
samer@2 138 end
samer@0 139
samer@2 140 function sched_wait
samer@2 141 while Timer.isrunning(); pause(0.05); end
samer@0 142 end