From Bcontrol
Revision as of 17:47, 22 September 2009 by Stuteja (talk | contribs)
% This is an example script showing how to use the @StateMachineAssembler
% object. It is a very simple example, and illustrates using scheduled
% waves. It doesn't use a trial structure-- the state machine keeps
% looping indefinitely.

% Written by Carlos Brody October 2006

% Updated by Sundeep Tuteja, September 22, 2009

% To get started to be able to run this script, (1) Get the ExperPort code
% from the CVS sever. Assuming you've already done this, (2) Start Matlab
% and change directory to the main ExperPort directory. (3) At the prompt,
% type
%    >> flush; mystartup;
% You should be good to go! NOTE: If you're going to run sounds on the Mac,
% also see Modules/@softsound/README.txt

% The following two lines are just to clear and close stuff in case
% you ran this script previously.
if exist('sm', 'var')
    Close(sm); clear sm;
if exist('sma', 'var')
    clear sma;

% This variable acquires its proper values in
% ExperPort/mystartup.m; if empty, it means we're on a virtual rig, not a
% real one:
global state_machine_server;

%Update by Sundeep Tuteja, September 22, 2009
%state_machine_server MUST COME FROM Settings_Custom.conf
assert(~exist('fid', 'var') && ~exist('strCurrentLine', 'var') && ~exist('findresult', 'var'))
assert(strcmpi(pwd), fullfile(getenv('HOMEDRIVE'), 'ratter', 'ExperPort'));
fid = fopen(fullfile('Settings', 'Settings_Custom.conf'), 'r+t');
while ~feof(fid)
    strCurrentLine = fgetl(fid);
    strCurrentLine = regexprep(strCurrentLine, '\s', '');
    findresult = strfind(strCurrentLine, 'state_machine_server;');
    if ~isempty(findresult)
        state_machine_server = strCurrentLine(length('RIGS;state_machine_server;')+1:end);
        state_machine_server = strrep(state_machine_server, ';', '');
clear('fid', 'strCurrentLine', 'findresult');
if strcmpi(state_machine_server, 'localhost') || strcmpi(state_machine_server, '')
    state_machine_server = [];

% Now set up the State Machine:
if isempty(state_machine_server)
    sm = SoftSMMarkII;
    sm = RTLSM2(state_machine_server);
sm = Initialize(sm);

% Ok, now set up an assembler:
sma = StateMachineAssembler;

% Let's declare two scheduled waves to start, the first with a two
% second preamble, the second with a 3-sec preamble. We give them two
% illustrative names; the names could be anything.
sma = add_scheduled_wave(sma, 'name', 'twosecs',  'preamble', 2);
sma = add_scheduled_wave(sma, 'name', 'threesecs','preamble', 3);

% Note: When you declare a wave with name "blah", the end of the
% preamble will cause a "blah_In" event. The end of the sustain will
% cause a "blah_Out" event. (See @RTLSM/SetScheduledWaves.m for an
% explanation of scheduled waves, and their preamble.)

% Now add the very first state (this'll be state 0). We won't give this
% state a name, since we'll just use it to pass through it on our way
% to the state that we'll name "base_state." When the state machine
% starts up, it'll start up already in State 0. Outputs are only
% set off when *entering* a state. So making sure that we *enter* the
% base_state when we start up  means that we make sure to trigger any
% outputs we want triggered in the base_state.
sma = add_state(sma, 'default_statechange', 'base_state', ...
    'self_timer', 0.001);

% Note: the default thing to do is to stay in your current state. The
% 'default_statechange' part above sets that to change to 'base_state', in
% response to *any* event, including Tup or anything else. We can use
% 'input_to_statechange' (see below) to indicate other possible states to
% jump to, in response to specific input events.

% Ok, now the start of the program. On entering this state, we start both
% the 2-sec and the 3-sec scheduled waves; and we turn on the left
% led. Furthermore, we specify that when a "twosec_In" event (from the
% 'twosec' scheduled wave) occurs, we should jump to a state that will be
% named "intermediate_state."
sma = add_state(sma, 'name', 'base_state', ...
    'output_actions', { ...
    'SchedWaveTrig', 'twosecs+threesecs' ; ...
    'DOut',          left1led            ; ...
    }, ...
    'input_to_statechange', { ...
    'twosecs_In', 'intermediate_state' ; ...

% This is a state we label 'intermediate_state' (for no good reason--
% names are arbitrary). Here we just wait for the 3-sec scheduled wave
% to go ping! At which point we jump to "alternate_state" (another
% arbitrary name).
sma = add_state(sma, 'name', 'intermediate_state', ...
    'input_to_statechange', { ...
    'threesecs_In', 'alternate_state' ; ...

% Let's declare a 1-sec scheduled wave that we'll use in alternate_state:
sma = add_scheduled_wave(sma, 'name', 'onesec',   'preamble', 1);

% In alternate_state, we turn on the right LED, and set off the 1-sec
% wave; also, when the one-sec wave goes ping! we jump back to
% base_state, to keep looping.
sma = add_state(sma, 'name', 'alternate_state', ...
    'output_actions', { ...
    'DOut',                right1led, ; ...
    'SchedWaveTrig', 'onesec' ; ...
    }, ...
    'input_to_statechange', { ...
    'onesec_In', 'base_state' ; ...

% Tell the assembler (sma) to assemble and send the program to the
% state machine (sm):
send(sma, sm);

% Ok! Start it up, and start at state 0 --standard intialization calls.
sm = Run(sm); sm = ForceState0(sm);

% Now run for 100 secs or so
oldevs = 0;
for i=1:1000,
    % Virtual state machine needs to periodically process its stuff:
    if isa(sm, 'SoftSMMarkII')
        sm = FlushQueue(sm);
    stevs = GetTimeEventsAndState(sm, 1);
    newevs = stevs.event_ct;
    if newevs ~= oldevs
        fprintf(1, 'FSM time is %g, and %d events have happened\n', stevs.time, newevs);
    oldevs = newevs;