Program FSMDemo7x10;
Uses Sysutils, keyboard, typinfo;
Type
t_State = (Start_State, S1, S2, S3, S4, S5, S6, S7, S8, S9, Delay_State, Exit_State);
t_Task = (T1, T2, T3, T4, T5, T6, T7);
Var //Required variables for the FSM and the Delay function
Task : t_Task; // Represents the actual active FSM
State : t_State; // Represents the actual state, most important variable of the FSM!!
States : Array[T1 .. T7] of t_State; //Store of state
Delay_Time : Array[T1 .. T7] of longint; //Common Delay Time per FSM
Delay_States : Array[T1 .. T7] of t_State; //Store of caller state is Delay is activated.
Millis, n, Loop_Time : longint; //Time in milli seconds
Const
Loop_Count = 1000;
//Application variables; can be removed
Var
X : Array[T1 .. T7] of integer;
Ch: String;
Delay_mS : longint; // app variable
(***************)
Procedure Change_State(Target: t_State); Forward;
Procedure Do_Delay_State; Forward;
Procedure Delay(t: longint); Forward;
(***************)
//All writeln / output and input statements are for demo only. Can be omitted.
(***************)
Procedure PL(s : string);
(***************)
var
i : integer;
Begin
for i := 0 to Ord(Task) - 1 do
write('*************');
writeln(' T: ' + GetEnumName(TypeInfo(t_Task), integer(Task)) + ' ' + s)
end;
(***************)
Procedure Print_Error(s : string);
(***************)
Begin
writeln('**************');
writeln(s);
writeln('**************');
end;
(***************)
Procedure Do_S1;
(***************)
Begin
PL('Do_S1, # ' + IntToStr(X[Task]));
X[Task]:= X[Task] + 1;
if X[Task] >= Ord(High(t_Task)) + 5 - Ord(Task) then
begin
Change_State(S2);
PL('My Delay = ' + IntToStr(Delay_mS + (1333 * Ord(Task))));
end
else
begin
Delay(Delay_mS + (1333 * Ord(Task)));
end;
end;
(***************)
Procedure Entry_S1;
(***************)
Begin
PL('Entry S1');
X[Task] := 0;
end;
(***************)
Procedure Exit_S1;
(***************)
Begin
PL('Exit S1');
end;
(***************)
Procedure Do_S2;
(***************)
Begin
PL('Do_S2, # ' + IntToStr(X[Task]));
X[Task]:= X[Task] + 1;
if X[Task] >= Ord(High(t_Task)) + 5 - Ord(Task) then
begin
Change_State(S3);
PL('My Delay = ' + IntToStr(Delay_mS + (1333 * Ord(Task))));
end
else
begin
Delay(Delay_mS + (1333 * Ord(Task)));
end;
end;
(***************)
Procedure Entry_S2;
(***************)
Begin
PL('Entry S2');
X[Task] := 0;
end;
(***************)
Procedure Exit_S2;
(***************)
Begin
PL('Exit S2');
end;
(***************)
Procedure Do_S3;
(***************)
Begin
PL('Do_S3, # ' + IntToStr(X[Task]));
X[Task]:= X[Task] + 1;
if X[Task] >= Ord(High(t_Task)) + 5 - Ord(Task) then
begin
Change_State(S4);
PL('My Delay = ' + IntToStr(Delay_mS + (1333 * Ord(Task))));
end
else
begin
Delay(Delay_mS + (1333 * Ord(Task)));
end;
end;
(***************)
Procedure Entry_S3;
(***************)
Begin
PL('Entry S3');
X[Task] := 0;
end;
(***************)
Procedure Exit_S3;
(***************)
Begin
PL('Exit S3');
end;
(***************)
Procedure Do_S4;
(***************)
Begin
PL('Do_S4, # ' + IntToStr(X[Task]));
X[Task]:= X[Task] + 1;
if X[Task] >= Ord(High(t_Task)) + 5 - Ord(Task) then
begin
Change_State(S5);
PL('My Delay = ' + IntToStr(Delay_mS + (1333 * Ord(Task))));
end
else
begin
Delay(Delay_mS + (1333 * Ord(Task)));
end;
end;
(***************)
Procedure Entry_S4;
(***************)
Begin
PL('Entry S4');
X[Task] := 0;
end;
(***************)
Procedure Exit_S4;
(***************)
Begin
PL('Exit S4');
end;
(***************)
Procedure Do_S5;
(***************)
Begin
PL('Do_S5, # ' + IntToStr(X[Task]));
X[Task]:= X[Task] + 1;
if X[Task] >= Ord(High(t_Task)) + 5 - Ord(Task) then
begin
Change_State(S6);
PL('My Delay = ' + IntToStr(Delay_mS + (1333 * Ord(Task))));
end
else
begin
Delay(Delay_mS + (1333 * Ord(Task)));
end;
end;
(***************)
Procedure Entry_S5;
(***************)
Begin
PL('Entry S5');
X[Task] := 0;
end;
(***************)
Procedure Exit_S5;
(***************)
Begin
PL('Exit S5');
end;
(***************)
Procedure Do_S6;
(***************)
Begin
PL('Do_S6, # ' + IntToStr(X[Task]));
X[Task]:= X[Task] + 1;
if X[Task] >= Ord(High(t_Task)) + 5 - Ord(Task) then
begin
Change_State(S7);
PL('My Delay = ' + IntToStr(Delay_mS + (1333 * Ord(Task))));
end
else
begin
Delay(Delay_mS + (1333 * Ord(Task)));
end;
end;
(***************)
Procedure Entry_S6;
(***************)
Begin
PL('Entry S6');
X[Task] := 0;
end;
(***************)
Procedure Exit_S6;
(***************)
Begin
PL('Exit S6');
end;
(***************)
Procedure Do_S7;
(***************)
Begin
PL('Do_S7, # ' + IntToStr(X[Task]));
X[Task]:= X[Task] + 1;
if X[Task] >= Ord(High(t_Task)) + 5 - Ord(Task) then
begin
Change_State(S8);
PL('My Delay = ' + IntToStr(Delay_mS + (1333 * Ord(Task))));
end
else
begin
Delay(Delay_mS + (1333 * Ord(Task)));
end;
end;
(***************)
Procedure Entry_S7;
(***************)
Begin
PL('Entry S7');
X[Task] := 0;
end;
(***************)
Procedure Exit_S7;
(***************)
Begin
PL('Exit S7');
end;
(***************)
Procedure Do_S8;
(***************)
Begin
PL('Do_S8, # ' + IntToStr(X[Task]));
X[Task]:= X[Task] + 1;
if X[Task] >= Ord(High(t_Task)) + 5 - Ord(Task) then
begin
Change_State(S9);
PL('My Delay = ' + IntToStr(Delay_mS + (1333 * Ord(Task))));
end
else
begin
Delay(Delay_mS + (1333 * Ord(Task)));
end;
end;
(***************)
Procedure Entry_S8;
(***************)
Begin
PL('Entry S8');
X[Task] := 0;
end;
(***************)
Procedure Exit_S8;
(***************)
Begin
PL('Exit S8');
end;
(***************)
Procedure Do_S9;
(***************)
Begin
PL('Do_S9, # ' + IntToStr(X[Task]));
X[Task]:= X[Task] + 1;
if X[Task] >= Ord(High(t_Task)) + 5 - Ord(Task) then
begin
Change_State(S1);
PL('My Delay = ' + IntToStr(Delay_mS + (1333 * Ord(Task))));
end
else
begin
Delay(Delay_mS + (1333 * Ord(Task)));
end;
end;
(***************)
Procedure Entry_S9;
(***************)
Begin
PL('Entry S9');
X[Task] := 0;
end;
(***************)
Procedure Exit_S9;
(***************)
Begin
PL('Exit S9');
end;
(***************)
Procedure Do_Delay_State__;
(***************)
Begin
PL('Do_Delay_State__, # ' + IntToStr(X[Task]));
X[Task]:= X[Task] + 1;
if X[Task] >= Ord(High(t_Task)) + 5 - Ord(Task) then
begin
Change_State(S2);
PL('My Delay = ' + IntToStr(Delay_mS + (1333 * Ord(Task))));
end
else
begin
Delay(Delay_mS + (1333 * Ord(Task)));
end;
end;
(***************)
Procedure Entry_Delay_State;
(***************)
Begin
PL('Entry Delay_State');
X[Task] := 0;
end;
(***************)
Procedure Exit_Delay_State;
(***************)
Begin
PL('Exit Delay_State');
end;
(***************)
Procedure Entries;
(***************)
Begin
Case State of
S1 : Entry_S1;
S2 : Entry_S2;
S3 : Entry_S3;
S4 : Entry_S4;
S5 : Entry_S5;
S6 : Entry_S6;
S7 : Entry_S7;
S8 : Entry_S8;
S9 : Entry_S9;
Delay_State : Entry_Delay_State;
Otherwise
Write(State); PL(' = Illegal Entry state');
end;
end;
(***************)
Procedure Exits;
(***************)
Begin
Case State of
S1 : Exit_S1;
S2 : Exit_S2;
S3 : Exit_S3;
S4 : Exit_S4;
S5 : Exit_S5;
S6 : Exit_S6;
S7 : Exit_S7;
S8 : Exit_S8;
S9 : Exit_S9;
Delay_State : Exit_Delay_State;
Otherwise
Write(State); PL(' = Illegal Exit state');
end;
end;
(***************)
Procedure Dispatch;
(***************)
Begin
Case State of
//Insert all possible states with Do-actions
S1 : Do_S1;
S2 : Do_S2;
S3 : Do_S3;
S4 : Do_S4;
S5 : Do_S5;
S6 : Do_S6;
S7 : Do_S7;
S8 : Do_S8;
S9 : Do_S9;
Delay_State : Do_Delay_State;
Otherwise
Print_Error('Illegal Dispatch state <' {+ Str(State)} + '>') ;
end;
end;
(***************)
Procedure Init_FSM_Vars;
(***************)
Begin
Delay_mS := 2000;
States[ T1 ] := S1;
State := S1;
Task := T1;
Entries;
States[ T2 ] := S2;
State := S2;
Task := T2;
Entries;
States[ T3 ] := S3;
State := S3;
Task := T3;
Entries;
States[ T4 ] := S4;
State := S4;
Task := T4;
Entries;
States[ T5 ] := S5;
State := S5;
Task := T5;
Entries;
States[ T6 ] := S6;
State := S6;
Task := T6;
Entries;
States[ T7 ] := S7;
State := S7;
Task := T7;
Entries;
End;
(***************)
Procedure Do_Delay_State; //This procedure will be generated double
(***************)
Var
KeyEvent: TKeyEvent;
Begin
if millis >= Delay_Time[Task] then
begin
State := Delay_States[Task]; //Return to caller state. No exits & entries !!
end
else
begin //This part is application dependent; in this case p resp m in/decreases the delay
if KeyPressed then
begin
ch := KeyEventToString(TranslateKeyEvent(getkeyevent));
PL('Key Char = <'+ ch + '>');
end
else
ch := '';
//write('<',ch,'>');
//readln;
if (ch = 'p' ) then
begin
Delay_mS := Delay_mS + 100;
Writeln('Delay_mS = ', Delay_mS);
end
else
if (ch = 'm' ) then
begin
Delay_mS := Delay_mS - 100;
if Delay_mS <= 0 then
Delay_mS := 100;
Writeln('Delay_mS = ', Delay_mS);
end
else
if ch = 'q' then
Change_State(Exit_State)
else
if ch = ' ' then
begin
beep;
writeln('More : ');
readln;
end;
ch := '';
initkeyboard;
end;
end;
(***************)
Procedure Delay(t : longint);
(***************)
Begin
Delay_States[Task] := State; //save this state
Delay_Time [Task] := millis + t;
State := Delay_State; // change to Do_Delay State.
end;
(***************)
Procedure Change_State(Target: t_State);
(***************)
Begin
// writeln('Change ', State, ' ====> ', Target);
Exits;
State := Target; //Change the complete state
Entries; //change to self-transition forces also an Exit & Entry
end;
(***************)
//Mainloop
(***************)
Begin
Init_FSM_vars;
// Change_state(Start_State); // Enter and Initiate starting state correctly
Writeln('Demo of a Finite State Machine with 7 tasks and 10 states, independently running');
Writeln('with different delay times and # of Do_actions per thread');
Writeln('Type m = accelerating; p = decelerating; q = exit; Space = Pause');
Writeln('Type Enter to start : ');
Readln;
n := Loop_Count + 1;
Loop_Time := 0;
Repeat
millis := DateTimeToTimeStamp(Now).time;
if n > Loop_Count then
begin
Writeln('====== Loop Time = ', (millis - Loop_Time),
' mS per ', Loop_Count, ' loops');
Loop_Time := millis;
n := 0;
end
else
begin
n := n + 1;
end;
//Do here some input action, that the FSM can react on
//Or let that action be done by interrupts of in other tasks in shared/static memory.
for Task := T1 to T7 do //Start the FSM´s of this demo.
begin
State := States[Task]; //restore the State
//Write('Task <', Task, '> ');
Dispatch; //Start the FSM
if State = Exit_State then Break;
States[Task] := State; //save the (new) State.
end;
sleep(9);
// Writeln('After Dispatch : ' ); Readln(Ch);
//Or do here some action (too)
until State = Exit_State;
Writeln('FSM Ready. Type Enter ');
Readln;
end.