# PIP: PIStateMachine< Type > Class Template Reference

PIStateMachine< Type > Class Template Reference

Base class for custom state machine. More...

Inheritance diagram for PIStateMachine< Type >:
[legend]

## Classes

struct | Rule
| Rule of transition between states of machine More...
struct | State
| State of machine More...

## Public Types

typedef PIPair< PIString, int > | Condition
| Condition is a pair (string, number)

## Public Member Functions

| PIStateMachine (void *_parent=0)
| Constructs an empty state machine.
void | addState (Type value, const PIString &name="", Handler handler=0)
| Add state of machine.
int | statesCount () const
| States count.
void | clearStates ()
| Remove all states.
void | addRule (Type from, Type to, const PIString &condition, Handler handler=0, bool autoTransition=false, bool resetAllConditions=false)
| Add rule of transition.
void | addRule (Type from, Type to, Handler handler, bool autoTransition=false, bool resetAllConditions=false)
| Add rule of transition.
void | addRule (Type from, Type to, const PIStringList &conditions=PIStringList(), Handler handler=0, bool autoTransition=false, bool resetAllConditions=false)
| Add rule of transition.
void | addRule (const Rule &rule)
| Add rule of transition.
int | rulesCount () const
| Rules count.
void | clearRules ()
| Remove all rules.
void | setInitialState (Type value)
| Setup initial state. reset() will set machine state to "value".
bool | switchToState (Type to)
| Try to switch machine state to state "to". More...
void | reset ()
| Reset machine state to initial and clear all conditions.
const State & | currentState () const
| Returns current state of machine.
void | resetConditions ()
| Reset all performed conditions.
void | resetCondition (const PIString &name)
| Reset performed condition with name "name".
void | performCondition (const PIString &name, int times=1)
| Perform condition with name "name" "times" times.
void | performConditions (const PIStringList &names)
| Perform every condition with name from "names" one time.
const PIVector< Condition > & | currentConditions () const
| Returns all current performed conditions.
Public Member Functions inherited from PIObject
| PIObject (const PIString &name=PIString())
| Contructs PIObject with name "name".
PIString | name () const
| Returns object name.
virtual const char * | className () const
| Returns object class name.
virtual const char * | superClassName () const
| Returns object superclass name.
bool | debug () const
| Return if debug of this object is active.
void | setName (const PIString &name)
| Set object name.
void | setDebug (bool debug)
| Set object debug active.
const PIMap< PIString, PIVariant > & | properties () const
| Returns properties of the object.
int | propertiesCount () const
| Returns properties count of the object.
PIVariant | property (const PIString &name) const
| Returns property with name "name".
void | setProperty (const PIString &name, const PIVariant &value)
| Set property with name "name" to "value". If there is no such property in object it will be added.
bool | isPropertyExists (const PIString &name) const
| Returns if property with name "name" exists.

## Protected Member Functions

virtual void | execution (const State &state)
| Reimplement this function to process current state of machine.
virtual void | transition (const State &from, const State &to)
| Reimplement this function to process switching current state of machine.
Protected Member Functions inherited from PIObject
PIObject * | emitter () const
| Returns PIObject* which has raised an event. This value is correct only in definition of some event handler.
virtual void | propertyChanged (const PIString &name)
| Virtual function executes after property with name "name" has been changed.
void | deleted ()
| Raise before object delete. More...

## Handlers

void | tick ()
| Main function of machine. Execute execution() and check if need to switch state.
void | tick (void *data, int delim)
| Main function of machine. Execute execution() and check if need to switch state.

## Additional Inherited Members

Static Public Member Functions inherited from PIObject
static void | piDisconnect (PIObject *src, const PIString &sig)
| Disconnect object "src" from all connections with event name "sig".
static void | piDisconnect (PIObject *src)
| Disconnect object "src" from all connections, i.e. all connections where object "src" is emitter.
static PIObject * | findByName (const PIString &name)
| Returns PIObject* with name "name" or 0, if there is no object found.
Related Functions inherited from PIObject
#define | piCoutObj
| Macro used for conditional (piDebug and PIObject::debug()) output to PICout for subclasses of PIObject.
#define | PIOBJECT(name)
| you should use this macro after class declaration to use EVENT and EVENT_HANDLER and correct piCoutObj output
#define | PIOBJECT_SUBCLASS(name, parent)
| you should use this macro after class declaration to use EVENT and EVENT_HANDLER of parent class
#define | EVENT_HANDLER0(ret, name) ret name()
| declare event handler "event" with name "name" and return type "ret", ret name()
#define | EVENT_HANDLER1(ret, name, type0, var0) ret name(type0 var0)
| declare event handler "event" with name "name" and return type "ret", ret name(type0 var0)
#define | EVENT_HANDLER2(ret, name, type0, var0, type1, var1) ret name(type0 var0, type1 var1)
| declare event handler "event" with name "name" and return type "ret", ret name(type0 var0, type1 var1)
#define | EVENT_HANDLER3(ret, name, type0, var0, type1, var1, type2, var2) ret name(type0 var0, type1 var1, type2 var2)
| declare event handler "event" with name "name" and return type "ret", ret name(type0 var0, type1 var1, type2 var2)
#define | EVENT_HANDLER4(ret, name, type0, var0, type1, var1, type2, var2, type3, var3) ret name(type0 var0, type1 var1, type2 var2, type3 var3)
| declare event handler "event" with name "name" and return type "ret", ret name(type0 var0, type1 var1, type2 var2, type3 var3)
#define | EVENT_HANDLER EVENT_HANDLER0
| EVENT_HANDLER is synonym of EVENT_HANDLER0.
#define | EVENT_VHANDLER0(ret, name) virtual ret name()
| declare virtual event handler "event" with name "name" and return type "ret", virtual ret name()
#define | EVENT_VHANDLER1(ret, name, type0, var0) virtual ret name(type0 var0)
| declare virtual event handler "event" with name "name" and return type "ret", virtual ret name(type0 var0)
#define | EVENT_VHANDLER2(ret, name, type0, var0, type1, var1) virtual ret name(type0 var0, type1 var1)
| declare virtual event handler "event" with name "name" and return type "ret", virtual ret name(type0 var0, type1 var1)
#define | EVENT_VHANDLER3(ret, name, type0, var0, type1, var1, type2, var2) virtual ret name(type0 var0, type1 var1, type2 var2)
| declare virtual event handler "event" with name "name" and return type "ret", virtual ret name(type0 var0, type1 var1, type2 var2)
#define | EVENT_VHANDLER4(ret, name, type0, var0, type1, var1, type2, var2, type3, var3) virtual ret name(type0 var0, type1 var1, type2 var2, type3 var3)
| declare virtual event handler "event" with name "name" and return type "ret", virtual ret name(type0 var0, type1 var1, type2 var2, type3 var3)
#define | EVENT_VHANDLER EVENT_VHANDLER0
| EVENT_VHANDLER is synonym of EVENT_VHANDLER0.
#define | EVENT0(name) void name();
| declare event "event" with name "name", void name();
#define | EVENT1(name, type0, var0) void name(type0 var0);
| declare event "event" with name "name", void name(type0 var0);
#define | EVENT2(name, type0, var0, type1, var1) void name(type0 var0, type1 var1);
| declare event "event" with name "name", void name(type0 var0, type1 var1);
#define | EVENT3(name, type0, var0, type1, var1, type2, var2) void name(type0 var0, type1 var1, type2 var2);
| declare event "event" with name "name", void name(type0 var0, type1 var1, type2 var2);
#define | EVENT4(name, type0, var0, type1, var1, type2, var2, type3, var3) void name(type0 var0, type1 var1, type2 var2, type3 var3);
| declare event "event" with name "name", void name(type0 var0, type1 var1, type2 var2, type3 var3);
#define | EVENT EVENT0
| EVENT is synonym of EVENT0.
#define | CONNECTU(src, event, dest, handler)
| connect event "event" from object "src" to event handler "handler". "Event" and "handler" must has equal argument lists.
#define | CONNECT0(ret, src, event, dest, handler)
| connect event "event" from object "src" to event handler "handler" with return type "ret" from object "dest" with check of event and handler exists
#define | CONNECT1(ret, type0, src, event, dest, handler)
| connect event "event" from object "src" to event handler "handler" with return type "ret" from object "dest" with check of event and handler exists
#define | CONNECT2(ret, type0, type1, src, event, dest, handler)
| connect event "event" from object "src" to event handler "handler" with return type "ret" from object "dest" with check of event and handler exists
#define | CONNECT3(ret, type0, type1, type2, src, event, dest, handler)
| connect event "event" from object "src" to event handler "handler" with return type "ret" from object "dest" with check of event and handler exists
#define | CONNECT4(ret, type0, type1, type2, type3, src, event, dest, handler)
| connect event "event" from object "src" to event handler "handler" with return type "ret" from object "dest" with check of event and handler exists
#define | CONNECT CONNECT0
| CONNECT is synonym of CONNECT0.
#define | WEAK_CONNECT0(ret, src, event, dest, handler)
| connect event "event" from object "src" to event handler "handler" with return type "ret" from object "dest" without check of event exists
#define | WEAK_CONNECT1(ret, type0, src, event, dest, handler)
| connect event "event" from object "src" to event handler "handler" with return type "ret" from object "dest" without check of event exists
#define | WEAK_CONNECT2(ret, type0, type1, src, event, dest, handler)
| connect event "event" from object "src" to event handler "handler" with return type "ret" from object "dest" without check of event exists
#define | WEAK_CONNECT3(ret, type0, type1, type2, src, event, dest, handler)
| connect event "event" from object "src" to event handler "handler" with return type "ret" from object "dest" without check of event exists
#define | WEAK_CONNECT4(ret, type0, type1, type2, type3, src, event, dest, handler)
| connect event "event" from object "src" to event handler "handler" with return type "ret" from object "dest" without check of event exists
#define | WEAK_CONNECT WEAK_CONNECT0
| WEAK_CONNECT is synonym of WEAK_CONNECT0.
#define | DISCONNECT0(ret, src, event, dest, handler)
| piDisconnect event "event" from object "src" from event handler "handler" with return type "ret" from object "dest"
#define | DISCONNECT1(ret, type0, src, event, dest, handler)
| piDisconnect event "event" from object "src" from event handler "handler" with return type "ret" from object "dest"
#define | DISCONNECT2(ret, type0, type1, src, event, dest, handler)
| piDisconnect event "event" from object "src" from event handler "handler" with return type "ret" from object "dest"
#define | DISCONNECT3(ret, type0, type1, type2, src, event, dest, handler)
| piDisconnect event "event" from object "src" from event handler "handler" with return type "ret" from object "dest"
#define | DISCONNECT4(ret, type0, type1, type2, type3, src, event, dest, handler)
| piDisconnect event "event" from object "src" from event handler "handler" with return type "ret" from object "dest"
#define | DISCONNECT DISCONNECT0
| DISCONNECT is synonym of DISCONNECT0.
#define | HANDLER(handler)
| Returns pointer to events handler "handler".

## Detailed Description

### template<typename Type = int>
class PIStateMachine< Type >

Base class for custom state machine.

# Synopsis

This class provide functionality of state machine. You should inherit from this class, implement execution() and transition() functions, set rules and periodically call tick() function to proper work of machine.

# Prepare for work

State machine operates with "state", "rule" and "condition".

- "State" is some class (by default `int`), associated name and optional "handler" - pointer to function executed on every tick();
- "Rule" define rule of transition from one machine state to other. It is also has optional "handler";
- "Condition" is a part of rule and define possibility of transition.

First of all you should define states of your machine by function addState(). Then you should define transition rules for machine by function addRule(). Finally you can set initial state by function setInitialState() and provide periodically execution of function tick().

# Principle of work

At any time the state machine is in some state. You can ask machine to enter in new state by function switchToState(). If all conditions done machine switch it state immediately, else machine remember request and will be try switch to the new state every tick. Successfull state switching execute function transition(), every tick execute function execution() with current state. On successfull transition if rule "handler" is not null it execute. Every tick() if current state "handler" is not null it execute.

# Conditions

Each rule has transition condition. Condition is array of pairs (string, number). It means that every condition by name "string" should be performed as least "number" times. Empty condition always permits transition.

State machine have current performed conditions. You can read this conditions by function currentConditions() and perform new conditions by functions performCondition() and performConditions(). Currend conditions can de erased by function resetConditions().

# Example

This is simple example demonstrates all features:

#include "pip.h"
enum Mode {Start, Manual, Auto, Finish, End};
class Machine: public PIStateMachine<Mode> {
PIOBJECT_SUBCLASS(Machine, PIObject)
public:
Machine() {
addState(Start, "start", HANDLER(startFunc));
addState(Manual, "manual", HANDLER(manualFunc));
addState(Auto, "auto", HANDLER(autoFunc));
addState(Finish, "finish", HANDLER(finishFunc));
addState(End, "end", HANDLER(endFunc));
addRule(Start, Manual, "init_ok", HANDLER(beginManualFunc));
addRule(Start, Auto, "init_ok", HANDLER(beginAutoFunc));
addRule(Manual, Auto, HANDLER(manualToAutoFunc));
addRule(Auto, Manual, HANDLER(autoToManualFunc));
addRule(Manual, Finish);
addRule(Auto, Finish);
Rule r(Finish, End);
r.addCondition("finish_0_ok");
r.addCondition("finish_1_ok", 2);
addRule(r);
setInitialState(Start);
CONNECT2(void, void*, int, &timer, timeout, this, tick);
timer.start(500);
}
virtual void execution(const State & state) {
piCout << "performed conditions:" << currentConditions();
}
virtual void transition(const State & from, const State & to) {
piCout << "switch from" << from.name << "to" << to.name << "state";
}
EVENT_HANDLER(void, startFunc) {piCout << "start function";}
EVENT_HANDLER(void, manualFunc) {piCout << "manual function";}
EVENT_HANDLER(void, autoFunc) {piCout << "auto function";}
EVENT_HANDLER(void, finishFunc) {piCout << "finish function";}
EVENT_HANDLER(void, endFunc) {piCout << "end function";}
EVENT_HANDLER(void, beginManualFunc) {piCout << "begin manual function";}
EVENT_HANDLER(void, beginAutoFunc) {piCout << "begin auto function";}
EVENT_HANDLER(void, autoToManualFunc) {piCout << "switch from auto to manual function";}
EVENT_HANDLER(void, manualToAutoFunc) {piCout << "switch from manual to auto function";}
PITimer timer;
};
Machine machine;
void key_event(char key, void*) {
switch (key) {
case 's': machine.switchToState(Start); break;
case 'm': machine.switchToState(Manual); break;
case 'a': machine.switchToState(Auto); break;
case 'f': machine.switchToState(Finish); break;
case 'e': machine.switchToState(End); break;
case '1': machine.performCondition("init_ok"); break;
case '2': machine.performCondition("finish_0_ok"); break;
case '3': machine.performCondition("finish_1_ok"); break;
case 'r': machine.resetConditions(); break;
case 'R': machine.reset(); break;
}
}
int main(int argc, char * argv[]) {
PIKbdListener kbd(key_event);
kbd.enableExitCapture();
WAIT_FOR_EXIT
};

## Member Function Documentation

template<typename Type = int>

bool PIStateMachine< Type >::switchToState | ( | Type | to | ) |

inline

Try to switch machine state to state "to".

If there is rule of transition exists and this rule conditions is performed then machine switched to new state immediately. Otherwise machine will be try to enter to new state every tick().

Returns
  `true` if state switched immediately, otherwise `false`