Here’s my attempt at implementing a Finite State Machine in RAPID. It’s just a skeleton example with a few typical states and state transitions. Comments or suggestions are welcome.
# MODULE MainModule
PROC main()
TPWriteProc "main","BEGIN";
FSM_Initialise;
FSM_StateRegister;
TPWriteProc "main","END";
ERROR
TPWriteProc "main.ERROR","@"\n:=ClkRead(clock1\HighRes);
ENDPROC
ENDMODULE
# MODULE FiniteStateMachine
ALIAS num StateID;
ALIAS string StateName;
RECORD State
StateID id;
StateName name;
bool transition;
StateID next_state_id;
ENDRECORD
!
! State Table
!
CONST StateID FSM_MAX_STATES:=6;
VAR State States{FSM_MAX_STATES}:=
[
[1,"EStop",FALSE,2],
[2,"Reset",FALSE,3],
[3,"Initialise",FALSE,4],
[4,"PickAndPlace",FALSE,5],
[5,"Done",FALSE,6],
[6,"Stop",FALSE,6]
];
VAR State current_state;
VAR State next_state;
VAR bool FSM_run:=TRUE;
PROC FSM_Initialise()
current_state:=States{1};
next_state:=States{1};
ENDPROC
FUNC bool FSM_IsValidState(State s)
VAR bool valid:=FALSE;
IF s.id>=1 AND s.id<=FSM_MAX_STATES THEN
valid:=TRUE;
ELSE
TPWriteProc "FSM_IsValidState","Invalid state="\n:=s.id;
FSM_run:=FALSE;
Stop;
ENDIF
RETURN valid;
ENDFUNC
PROC FSM_NextStateLogic()
VAR bool valid_state:=FALSE;
VAR bool transition:=FALSE;
valid_state:=FSM_IsValidState(current_state);
IF valid_state THEN
transition:=current_state.transition;
IF transition THEN
! Reset transition flag of current state.
current_state.transition:=FALSE;
! Reset transition flag of next state.
States{current_state.next_state_id}.transition:=FALSE;
! Select next state.
current_state:=States{current_state.next_state_id};
ENDIF
ENDIF
ENDPROC
PROC FSM_OutputLogic()
VAR bool valid_state:=FALSE;
VAR string call_routine;
valid_state:=FSM_IsValidState(current_state);
IF valid_state THEN
!CallByVar "FSM_State",FSM_current_state;
call_routine:="FiniteStateMachine_States:FSM_State_"+current_state.name;
%call_routine %;
current_state.transition:=TRUE;
ENDIF
ERROR
IF ERRNO=ERR_CALLPROC THEN
TPWriteProc "FSM_OutputLogic","Routine not defined: "+call_routine;
Stop;
ENDIF
ENDPROC
PROC FSM_StateRegister()
WHILE FSM_run DO
TPWriteProc "FSM_StateRegister","cycle@"\n:=ClkRead(clock1\HighRes);
FSM_OutputLogic;
FSM_NextStateLogic;
ENDWHILE
Stop;
ENDPROC
ENDMODULE
# MODULE FiniteStateMachine_States
!
! BEGIN: Routines for the states defined in the state table.
!
PROC FSM_State_EStop()
ENDPROC
PROC FSM_State_Reset()
ENDPROC
PROC FSM_State_Initialise()
ENDPROC
PROC FSM_State_PickAndPlace()
ENDPROC
PROC FSM_State_Done()
ENDPROC
PROC FSM_State_Stop()
ENDPROC
!
! END: Routines for the states defined in the state table.
!
ENDMODULE
# MODULE Helper PROC TPWriteProc(string sProcName,string s,\num n|bool b|pos p|orient o|dnum d)
VAR string str;
str:=sProcName+" "+s;
IF Present(n) THEN
TPWrite str\num:=n;
ELSEIF Present(b) THEN
TPWrite str\bool:=b;
ELSEIF Present(p) THEN
TPWrite str\pos:=p;
ELSEIF Present(o) THEN
TPWrite str\orient:=o;
ELSEIF Present(d) THEN
TPWrite str\dnum:=d;
ELSE
TPWrite str;
ENDIF
ERROR
TPWrite "TPWriteProc.ERROR @"\num:=ClkRead(clock1\HighRes);
ENDPROC
ENDMODULE