/////////////////////////////////////////////////////////////////////////////

//

// File: FSMSample.cpp

//

// Created by MOON, Eui-kwon.

// Created on Aug-10th, 2011.

//

// 교육용으로작성한FSM Sample.

// 예전에FSM 공부할때cdplayer라는샘플코드를본것같은데코드는없고

// 웹에상태천이표만있어서그기준으로코드를작성함.

//

// machine, state, event 각각의인터페이스는비지터패턴형식으로구성함.

//

/////////////////////////////////////////////////////////////////////////////

//===========================================================================

 

 

 

#include "stdafx.h"

#include <assert.h>

 

/////////////////////////////////////////////////////////////////////////////

//

// Finite state machine

//

/////////////////////////////////////////////////////////////////////////////

//===========================================================================

namespace fsm

{

 

 

 

/////////////////////////////////////////////////////////////////////////////

//===========================================================================

class event;

class state;

class machine;

 

 

 

/////////////////////////////////////////////////////////////////////////////

//

// Interface

//

/////////////////////////////////////////////////////////////////////////////

//===========================================================================

class machine

{

private:

        state* _state;

       

public:

        machine();

        virtual ~machine();

 

public:

        virtual void   transition (state*);

        virtual void   notify     (event*);

        virtual state* get_state  (void  ) const;

};

 

/////////////////////////////////////////////////////////////////////////////

//===========================================================================

class event

{

public:

        event();

        virtual ~event();

 

public:

        virtual void notify (machine*, state*);

};

 

/////////////////////////////////////////////////////////////////////////////

//===========================================================================

class state

{

public:

        state();

        virtual ~state();

       

public:

        virtual void on_entry   (machine*, state*);

        virtual void on_exit    (machine*, state*);

        virtual void on_event   (machine*, event*);

 

public:

        virtual void transition (machine*, state*);

};

 

 

 

 

/////////////////////////////////////////////////////////////////////////////

//

// Implementation

//

/////////////////////////////////////////////////////////////////////////////

//===========================================================================

event:: event(){}

event::~event(){}

 

void event::notify (machine* m, state*s)

{

        if (s)

        {

               s->on_event (m, this);

        }

}

 

//===========================================================================

state:: state(){}

state::~state(){}

 

void state::on_entry (machine*, state*) {}

void state::on_exit  (machine*, state*) {}

void state::on_event (machine*, event*) {}

 

void state::transition (machine* m, state* s)

{

        if (m)

        {

               m->transition (s);

        }

}

 

//===========================================================================

machine::machine():

        _state (0)

{

}

 

machine::~machine()

{

}

 

state* machine::get_state (void) const

{

        return _state;

}

 

void machine::transition (state* current)

{      

        state* previous;

 

        previous = _state;

        if (previous)

        {

               previous->on_exit (this, current );

        }

 

        _state = current;

        if (current)

        {

               current ->on_entry (this, previous);

        }

}

 

void machine::notify (event* e)

{

        if (e)

        {

               e->notify (this, _state);

        }

}

 

}; // end of "namespace fsm"

 

 

 

/////////////////////////////////////////////////////////////////////////////

//

// Sample

//

/////////////////////////////////////////////////////////////////////////////

//===========================================================================

#define fsm_trace  printf

#define fsm_assert assert

 

//===========================================================================

enum cdplayer_event_code_t

{

        ec_play        = 0,

        ec_open_close  = 1,

        ec_cd_detected = 2,

        ec_stop        = 3,

        ec_pause       = 4

};

 

//===========================================================================

class cdplayer_event : public fsm::event

{

public:

        const cdplayer_event_code_t _code;

 

        explicit cdplayer_event (cdplayer_event_code_t code) : _code(code)

        {

        }

 

        void notify (fsm::machine* m, fsm::state*s)

        {

               switch (_code)

               {

               case ec_play       : fsm_trace("\t\tnotify: play        \r\n"); break;

               case ec_open_close : fsm_trace("\t\tnotify: open_close  \r\n"); break;

               case ec_cd_detected: fsm_trace("\t\tnotify: cd_detected \r\n"); break;

               case ec_stop       : fsm_trace("\t\tnotify: stop        \r\n"); break;

               case ec_pause      : fsm_trace("\t\tnotify: pause       \r\n"); break;

               }

 

               fsm::event::notify (m, s);

        }

};

 

//===========================================================================

class cdplayer_state : public fsm::state

{

public:

        virtual const char* get_name (void) = 0;

 

        virtual void on_event (fsm::machine* m, fsm::event* e)

        {

               /*

               cdplayer*       cm = static_cast<cdplayer*      > ( m );

               cdplayer_event* ce = static_cast<cdplayer_event*> ( e );

 

               switch (ce->_code)

               {

               case ec_play       : break;

               case ec_open_close : break;

               case ec_cd_detected: break;

               case ec_stop       : break;

               case ec_pause      : break;

               }

               */

        }

 

        virtual void on_entry (fsm::machine*, fsm::state*)

        {

               fsm_trace("\ton_entry: %s \r\n", get_name());

        }

 

        virtual void on_exit (fsm::machine*, fsm::state*)

        {

               fsm_trace("\ton_exit : %s \r\n", get_name());

        }

};

#define DECLARE_NAME(n) virtual const char* get_name (void) { return (n); }

 

//===========================================================================

class stopped: public cdplayer_state

{

public:

        DECLARE_NAME ("stopped" )

        virtual void on_event (fsm::machine* m, fsm::event* e);

};

 

//===========================================================================

class open: public cdplayer_state

{

public:

        DECLARE_NAME ("open" )

        virtual void on_event (fsm::machine* m, fsm::event* e);

};

 

//===========================================================================

class empty: public cdplayer_state

{

public:

        DECLARE_NAME ("empty" )

        virtual void on_event (fsm::machine* m, fsm::event* e);

};

 

//===========================================================================

class playing: public cdplayer_state

{

public:

        DECLARE_NAME ("playing" )

        virtual void on_event (fsm::machine* m, fsm::event* e);

};

 

//===========================================================================

class paused: public cdplayer_state

{

public:

        DECLARE_NAME ("paused" )

        virtual void on_event (fsm::machine* m, fsm::event* e);

};

 

//===========================================================================

class cdplayer: public fsm::machine

{

private:

        stopped _stopped;

        open    _open   ;

        empty   _empty  ;

        playing _playing;

        paused  _paused ;

 

public:

        enum state_id_t

        {

               sid_stopped,

               sid_open   ,

               sid_empty  ,

               sid_playing,

               sid_paused ,

        };

 

public:

        virtual void transition (fsm::state* n)

        {

               cdplayer_state* previous = static_cast<cdplayer_state*> ( get_state() );

               cdplayer_state* current  = static_cast<cdplayer_state*> ( n );

 

               fsm_trace ("transition:");

               if (previous) fsm_trace (" %s -> ", previous->get_name());

               if (current ) fsm_trace (" %s ", current ->get_name());

               fsm_trace ("\r\n");

 

               fsm::machine::transition(n);

        }

 

        cdplayer_state* get_state_instance (state_id_t id)

        {

               switch (id)

               {

               case sid_stopped : return &_stopped ;

               case sid_open    : return &_open    ;

               case sid_empty   : return &_empty   ;

               case sid_playing : return &_playing ;

               case sid_paused  : return &_paused  ;

               }

 

               fsm_assert (0);

 

               return 0;

        }

 

public:

        void start_playback         (void){ printf("\t\t\taction: start_playback         \r\n"); }

        void open_drawer            (void){ printf("\t\t\taction: open_drawer            \r\n"); }

        void close_drawer           (void){ printf("\t\t\taction: close_drawer           \r\n"); }

        void collect_cd_information (void){ printf("\t\t\taction: collect_cd_information \r\n"); }

        void store_cd_information   (void){ printf("\t\t\taction: store_cd_information   \r\n"); }

        void stop_playback          (void){ printf("\t\t\taction: stop_playback          \r\n"); }

        void pause_playback         (void){ printf("\t\t\taction: pause_playback         \r\n"); }

        void resume_playback        (void){ printf("\t\t\taction: resume_playback        \r\n"); }

};

 

/*********************************************************************************

 CD PLAYER STATE TRANSITION TABLE

---------------+-------------+------------+--------------------------------------

 CURRENT STATE | EVENT       | NEXT STATE | TRANSITION ACTION

---------------+-------------+------------+--------------------------------------

 stopped       | play        | playing    | start playback

 stopped       | open/close  | open       | open drawer

 open          | open/close  | empty      | close drawer; collect cd information

 empty         | open/close  | open       | open drawer

 empty         | cd-detected | stopped    | store cd information

 playing       | stop        | stopped    | stop playback

 playing       | pause       | paused     | pause playback

 playing       | open/close  | open       | stop playback; open drawer

 paused        | play        | playing    | resume playback

 paused        | stop        | stopped    | stop playback

 paused        | open/close  | open       | stop playback; open drawer

---------------+-------------+------------+--------------------------------------

*********************************************************************************/

 

//===========================================================================

void stopped::on_event (fsm::machine* m, fsm::event* e)

{

        cdplayer*       cm = static_cast<cdplayer*      > ( m );

        cdplayer_event* ce = static_cast<cdplayer_event*> ( e );

 

        switch (ce->_code)

        {

        case ec_play :

               cm->start_playback();

               transition(cm, cm->get_state_instance (cdplayer::sid_playing));

               break;

 

        case ec_open_close :

               cm->open_drawer ();

               transition(cm, cm->get_state_instance (cdplayer::sid_open));

               break;

        }

}

 

//===========================================================================

void open::on_event (fsm::machine* m, fsm::event* e)

{

        cdplayer*       cm = static_cast<cdplayer*      > ( m );

        cdplayer_event* ce = static_cast<cdplayer_event*> ( e );

 

        switch (ce->_code)

        {

        case ec_open_close :

               cm->close_drawer();

               cm->collect_cd_information();

               transition(cm, cm->get_state_instance (cdplayer::sid_empty));

               break;

        }

}

 

//===========================================================================

void empty::on_event (fsm::machine* m, fsm::event* e)

{

        cdplayer*       cm = static_cast<cdplayer*      > ( m );

        cdplayer_event* ce = static_cast<cdplayer_event*> ( e );

 

        switch (ce->_code)

        {

        case ec_open_close :

               cm->open_drawer();

               transition(cm, cm->get_state_instance (cdplayer::sid_open));

               break;

 

        case ec_cd_detected:

               cm->store_cd_information();

               transition(cm, cm->get_state_instance (cdplayer::sid_stopped));

               break;

        }

}

 

//===========================================================================

void playing::on_event (fsm::machine* m, fsm::event* e)

{

        cdplayer*       cm = static_cast<cdplayer*      > ( m );

        cdplayer_event* ce = static_cast<cdplayer_event*> ( e );

 

        switch (ce->_code)

        {

        case ec_stop :

               cm->stop_playback();

               transition(cm, cm->get_state_instance (cdplayer::sid_stopped));

               break;

 

        case ec_pause :

               cm->pause_playback();

               transition(cm, cm->get_state_instance (cdplayer::sid_paused));

               break;

 

        case ec_open_close :

               cm->stop_playback();

               cm->open_drawer();

               transition(cm, cm->get_state_instance (cdplayer::sid_open));

               break;

        }

}

//===========================================================================

void paused::on_event (fsm::machine* m, fsm::event* e)

{

        cdplayer*       cm = static_cast<cdplayer*      > ( m );

        cdplayer_event* ce = static_cast<cdplayer_event*> ( e );

 

        switch (ce->_code)

        {

        case ec_play :

               cm->resume_playback();

               transition(cm, cm->get_state_instance (cdplayer::sid_playing));

               break;

 

        case ec_stop :

               cm->stop_playback();

               transition(cm, cm->get_state_instance (cdplayer::sid_stopped));

               break;

 

        case ec_open_close :

               cm->stop_playback();

               cm->open_drawer();

               transition(cm, cm->get_state_instance (cdplayer::sid_open));

               break;

        }

}

//===========================================================================

int _tmain(int argc, _TCHAR* argv[])

{

        cdplayer       player;

        cdplayer_event play        (ec_play       );

        cdplayer_event open_close  (ec_open_close );

        cdplayer_event cd_detected (ec_cd_detected);

        cdplayer_event stop        (ec_stop       );

        cdplayer_event pause       (ec_pause      );

 

        player.transition ( player.get_state_instance(cdplayer::sid_empty) );

 

        player.notify ( &cd_detected );

        player.notify ( &play        );

        player.notify ( &pause       );

        player.notify ( &stop        );

        player.notify ( &open_close  );

        player.notify ( &stop        );

        player.notify ( &play        );

        player.notify ( &open_close  );

 

        player.notify ( &open_close  );

        player.notify ( &cd_detected );

        player.notify ( &play        );

 

        return 0;

}

 

/////////////////////////////////////////////////////////////////////////////

//

// result

//

/////////////////////////////////////////////////////////////////////////////

//===========================================================================

/*

transition: empty

        on_entry: empty

                notify: cd_detected

                        action: store_cd_information

transition: empty ->  stopped

        on_exit : empty

        on_entry: stopped

                notify: play

                        action: start_playback

transition: stopped ->  playing

        on_exit : stopped

        on_entry: playing

                notify: pause

                        action: pause_playback

transition: playing ->  paused

        on_exit : playing

        on_entry: paused

                notify: stop

                        action: stop_playback

transition: paused ->  stopped

        on_exit : paused

        on_entry: stopped

                notify: open_close

                        action: open_drawer

transition: stopped ->  open

        on_exit : stopped

        on_entry: open

                notify: stop

                notify: play

                notify: open_close

                        action: close_drawer

                        action: collect_cd_information

transition: open ->  empty

        on_exit : open

        on_entry: empty

                notify: open_close

                        action: open_drawer

transition: empty ->  open

        on_exit : empty

        on_entry: open

                notify: cd_detected

                notify: play

계속하려면아무키나누르십시오. . .

*/

 

 

Posted by 셈말짓기 :