Skip to content

eliangidoni/HSMgen

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

    HSMgen reads FSM definitions (in a mini-language) and generates C++ source
    code. The generated code defines interfaces for each FSM and its
    states. Transitions have associated guard conditions evaluated before
    execution and every state triggers (optional) enter/exit actions.


                                  Dependencies

1) Java 1.6.
2) ANTLR 4 runtime (included in src/).


                                     Build

$ cd src
$ . antlr-vars.sh
$ javac HSMgenLexer.java HSMgenParser.java HSMgen.java


                                     Usage

$ java HSMgen <file>

Testing the FSM 'example.fsm',

$ java HSMgen ../example.fsm > ../example.h
$ cd ..
$ g++ example.cpp -o example
$ ./example


                                    Example

1) FSM code generation

Given the input file,

fsm-info example
{
    example_init
    {
        theEvent -> finished;
    }
    finished
    {
    }
}

The (relevant) C++ generated code would be,

class Event
{
public:
    int evCode;
};

class ExampleInitState
{
public:
    virtual ~ExampleInitState(){ }
    virtual void enterExampleInitState(){ }
    virtual void exitExampleInitState(){ }

    virtual bool theEvent_then_finished_guard(Event *e)=0;
    virtual FinishedState* theEvent_then_finished(Event *e)=0;

};

class FinishedState
{
public:
    virtual ~FinishedState(){ }
    virtual void enterFinishedState(){ }
    virtual void exitFinishedState(){ }

};

class ExampleFsmState
{
public:
    virtual ~ExampleFsmState(){ }
    virtual void enterExampleFsmState()=0;
    virtual void exitExampleFsmState()=0;
};

class ExampleFsm : public FsmState
{
public:
    enum EventCode {
        EVENT_THEEVENT = 0,
    };
    void init(ExampleInitState* s, ExampleFsmState*fsmState);
    virtual void enter();
    virtual void exit();
    virtual bool sendEvent(Event *e);
};

2) Initializing the FSM

Every FSM has an init() function that receives two arguments:
    - The FSM initial state implementation
    - The FSM enter/exit actions (optional, can be NULL)

Before sending any event enter() must be called. Similarly, when the FSM is no
longer needed exit() must be called.
NOTE: calls to enter() and exit() aren't needed for any FSM that is a nested
state (i.e. returned by a state).

3) Sending events

Events are sent with sendEvent() which returns true if the event was handled,
false otherwise (i.e. whether there is a valid transition).
The following code sends event 'theEvent' to the above FSM 'ExampleFsm'.

ExampleFsm f;
Event e;
f.init(...);
f.enter();

e.evCode = ExampleFsm::EVENT_THEEVENT;
f.sendEvent(&e);

f.exit();


                               FSM mini-language

1) Flat format

fsm-info <FSM_NAME> {
    <STATE_1> {
        <EVENT_1> -> <STATE_X> ;
        .
        . 
        <EVENT_N> -> <STATE_X> ;
    }
    .
    .
    <STATE_N> {
        .
        .
    }
}

2) Hierarchical/Nested format

fsm-info <FSM_NAME> (<NESTED_1>, .., <NESTED_N>) {
    <STATE_1> {
        <EVENT_1> -> <NESTED_X> ;
        .
        . 
    }
    .
    .
}

3) Additional notes

- The first defined FSM state is its initial state.
- State names are global in scope, avoid duplicating them.
- State names should be in lower case with optional underscores
  (e.g. 'some_state').
- Transition events should be in camel case (e.g. 'someEvent').
- A state can have zero transitions (e.g. 'some_state{ }').