简体   繁体   中英

Boost MSM process_event doesn't transit between SM states

I've created a HSM using boost MSM.

Diagram:
在此处输入图像描述 Code:

#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/back/tools.hpp>
#include <boost/msm/front/euml/operator.hpp>
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>

// TODO - move this from here to different module
struct EventConfigure {};
struct EventSendDetailsRsp {};

struct EventSendGrantsRsp {};
struct EventGetGrantsRsp {};
struct EventGetStatsRsp {};
struct EventCycleTimeout {};
struct EventStartWaitTimerExpired {};
struct EventGapTimerExpired {};

// ---------------------- CYCLING STATE MACHINE----------------------//


/* Internal Cycling SM */
struct CyclingSm_
        : msmf::state_machine_def<CyclingSm_> {

    CyclingSm_() {}

    struct FillingDetails : msmf::state<> {

        template <class Event, class Fsm>
        void on_entry(const Event& rEvent, Fsm& rFsm) const
        {
            // add here name maybe
            LOG4CXX_INFO(Logger(), "FillingDetails::on_entry");

        }

        template <class Event, class Fsm>
        void on_exit(const Event& rEvent, Fsm& rFsm) const
        {
            LOG4CXX_INFO(Logger(), "FillingDetails::on_exit");
        }

    };


    struct SendingGrants : msmf::state<> {


        template <class Event, class Fsm>
        void on_entry(const Event& rEvent, Fsm& rFsm) const
        {
            // add here name maybe
            LOG4CXX_INFO(Logger(), "SendingGrants::on_entry");
        }

        template <class Event, class Fsm>
        void on_exit(const Event& rEvent, Fsm& rFsm) const
        {
            LOG4CXX_INFO(Logger(), "SendingGrants::on_exit");
        }
    };


    struct GettingGrants : msmf::state<> {

        template <class Event, class Fsm>
        void on_entry(const Event& rEvent, Fsm& rFsm) const
        {
            // add here name maybe
            LOG4CXX_INFO(Logger(), "GettingGrants::on_entry");
        }

        template <class Event, class Fsm>
        void on_exit(const Event& rEvent, Fsm& rFsm) const
        {
            LOG4CXX_INFO(Logger(), "GettingGrants::on_exit");
        }
    };

    template <class Event, class Fsm>
    void on_entry(const Event& rEvent, Fsm& rFsm) const
    {
        // add here name maybe
        LOG4CXX_INFO(Logger(), "CyclingSm::on_entry");

        // Need to prepare here the next cycle (cms_groups)

    }

    template <class Event, class Fsm>
    void on_exit(const Event& rEvent, Fsm& rFsm) const
    {
        LOG4CXX_INFO(Logger(), "CyclingSm::on_exit");
    }

    struct PseudoCycleExit : public msmf::exit_pseudo_state<msmf::none> {};

    typedef FillingDetails initial_state;

    struct transition_table : mpl::vector<
    //         Start                            Event                         Next                               Action                                          Guard
    //        +-------------------------------+-----------------------------+----------------------------------+----------------------------------------------+----------+
    msmf::Row<FillingDetails,                  EventSendDetailsRsp,           SendingGrants,                     msmf::none,                                     msmf::none>,
    //        +-------------------------------+-----------------------------+----------------------------------+-----------------------------------------------+----------+
    msmf::Row<SendingGrants,                   EventSendGrantsRsp,            GettingGrants,                     msmf::none,                                     msmf::none>,
    //        +-------------------------------+-----------------------------+----------------------------------+------------------------------------------------+----------+
    msmf::Row<GettingGrants,                   EventGetGrantsRsp,             PseudoCycleExit,                   msmf::none,                                     msmf::none>

    >, OBJECTS_COUNTER(transition_table) {};


    template<class Fsm, class Event>
    void no_transition(Event const& e, Fsm& rFsm, int state)
    {
        typedef typename Fsm::stt Stt;
        typedef typename msm::back::generate_state_set<Stt>::type all_states; //all states
        std::string state_name;
        // fill state_name for state
        boost::mpl::for_each<all_states,boost::msm::wrap<mpl::placeholders::_1> >
                  (msm::back::get_state_name<Stt>(state_name, state));

         LOG4CXX_WARN(Logger(), "no_transition from state " << state_name << " by event " << typeid(e).name());
    }

    template <class Fsm, class Event>
    void exception_caught (Event const& event, Fsm& rFsm, const std::exception& e)
    {
        LOG4CXX_ERROR(Logger(), " exception_caught: " << e.what() <<" by event " << typeid(event).name());
    }

}; // CyclingSm_

typedef msm::back::state_machine<CyclingSm_> CyclingSm;

// ----------------- OUTER STATE MACHINE ---------------//

struct OuterSm_
        : msmf::state_machine_def<OuterSm_>  {

    OuterSm_() {}

    struct StateStandby : msmf::state<> {

        template <class Event, class Fsm>
        void on_entry(const Event& rEvent, Fsm& rFsm) const
        {
            // add here name maybe
            LOG4CXX_INFO(Logger(), "StateStandby::on_entry");
        }

        template <class Event, class Fsm>
        void on_exit(const Event& rEvent, Fsm& rFsm) const
        {
            LOG4CXX_INFO(Logger(), "StateStandby::on_exit");
        }

    };

    struct StateStartWaiting : msmf::state<> {

        template <class Event, class Fsm>
        void on_entry(const Event& rEvent, Fsm& rFsm) const
        {
            // add here name maybe
            LOG4CXX_INFO(Logger(), "StateStartWaiting::on_entry");
        }

        template <class Event, class Fsm>
        void on_exit(const Event& rEvent, Fsm& rFsm) const
        {
            LOG4CXX_INFO(Logger(), "StateStartWaiting::on_exit");
        }

    };

    // ---------------------- OPERATIONAL STATE MACHINE----------------------//

    struct OperationalSm_ : msmf::state_machine_def<OperationalSm_> {

        OperationalSm_() {}

        struct GettingStats : msmf::state<> {


            template <class Event, class Fsm>
            void on_entry(const Event& rEvent, Fsm& rFsm) const
            {
                // add here name maybe
                LOG4CXX_INFO(Logger(), "GettingStats::on_entry");
            }

            template <class Fsm>
            void on_exit(const EventGetStatsRsp& rEvent, Fsm& rFsm) const
            {
                LOG4CXX_INFO(Logger(), "GettingStats::on_exit (EventGetStatsRsp)");
            }

            template <class Event, class Fsm>
            void on_exit(const Event& rEvent, Fsm& rFsm) const
            {
                LOG4CXX_INFO(Logger(), "GettingStats::on_exit");
            }
        };

        struct GapWaiting : msmf::state<> {


            template <class Event, class Fsm>
            void on_entry(const Event& rEvent, Fsm& rFsm) const
            {
                // add here name maybe
                LOG4CXX_INFO(Logger(), "GapWaiting::on_entry");
            }

            template <class Event, class Fsm>
            void on_exit(const Event& rEvent, Fsm& rFsm) const
            {
                LOG4CXX_INFO(Logger(), "GapWaiting::on_exit");
            }
        };

        template <class Event, class Fsm>
        void on_entry(const Event& rEvent, Fsm& rFsm) const
        {
            // add here name maybe
            LOG4CXX_INFO(Logger(), "Operational::on_entry");
        }

        template <class Event, class Fsm>
        void on_exit(const Event& rEvent, Fsm& rFsm) const
        {
            LOG4CXX_INFO(Logger(), "Operational::on_exit");
        }


        struct GuardStatsTimerExpired {
            template <class Event, class Fsm, class SRC, class DST>
            bool operator()(const Event& rEvent, const Fsm& rFsm, const SRC&, const DST&)
            {
                LOG4CXX_INFO(Logger(), "GuardStatsTimerExpired");
                return true;
            }
        };

        // Struct defining cycling sub-state
        struct Cycling : CyclingSm {
            Cycling() : CyclingSm() {}
        };

        typedef GettingStats initial_state;

        struct transition_table:mpl::vector<
        //         Start                                Event                          Next                    Action           Guard
        //        +------------------------------------+------------------------------+-----------------------+----------------+---------+
        msmf::Row<Cycling::exit_pt
                      <Cycling::PseudoCycleExit>,        msmf::none,                    GapWaiting,            msmf::none,      msmf::none>,
        msmf::Row<GapWaiting,                            EventGapTimerExpired,          GettingStats,    msmf::none,      GuardStatsTimerExpired>,
        msmf::Row<GapWaiting,                            EventGapTimerExpired,          CyclingSm,             msmf::none,      msmf::none>,
        msmf::Row<GettingStats,                          EventGetStatsRsp,              CyclingSm,             msmf::none,      msmf::none>

        >, OBJECTS_COUNTER(transition_table) {};


        template<class Fsm, class Event>
        void no_transition(Event const& e, Fsm& rFsm, int state)
        {
            typedef typename Fsm::stt Stt;
            typedef typename msm::back::generate_state_set<Stt>::type all_states; //all states
            std::string state_name;
            // fill state_name for state
            boost::mpl::for_each<all_states,boost::msm::wrap<mpl::placeholders::_1> >
                      (msm::back::get_state_name<Stt>(state_name, state));

             LOG4CXX_WARN(Logger(), "no_transition from state "
                                                             << state_name << " by event "
                                                             << typeid(e).name());
        }

        template <class Fsm, class Event>
        void exception_caught (Event const& event, Fsm& rFsm, const std::exception& e)
        {
            LOG4CXX_ERROR(Logger(), " exception_caught: " << e.what() <<" by event " << typeid(event).name());
        }

    }; // OperationalSm_

    typedef msm::back::state_machine<OperationalSm_> OperationalSm;

    struct GuardEnabled {
        template <class Event, class Fsm, class SRC, class DST>
        bool operator()(const Event& rEvent, Fsm& rFsm, SRC&, DST&) const
        {
            LOG4CXX_INFO(Logger(), "GuardEnabled");
            return true;
        }
    };

    struct GuardWithinCurrentCycleInterval {
        template <class Event, class Fsm, class SRC, class DST>
        bool operator()(const Event& rEvent, Fsm& rFsm, SRC&, DST&)
        {
            LOG4CXX_INFO(Logger(), "GuardWithinCurrentCycleInterval");
            return true;
        }
    };

    struct GuardWithinFutureCycleInterval {
        template <class Event, class Fsm, class SRC, class DST>
        bool operator()(const Event& rEvent, Fsm& rFsm, SRC&, DST&)
        {
            LOG4CXX_INFO(Logger(), "GuardWithinFutureCycleInterval");
            return false;
        }
    };

    using GuardIsEnabledAndWithinCurrentCyclingInterval = msmf::euml::And_<GuardEnabled, GuardWithinCurrentCycleInterval>;
    using GuardIsEnabledAndWithinFutureCyclingInterval = msmf::euml::And_<GuardEnabled, GuardWithinFutureCycleInterval>;

    typedef StateStandby initial_state;

    struct transition_table : mpl::vector<
    //         Start                              Event                        Next                               Action            Guard
    //        +----------------------------------+---------------------------+----------------------------------+-----------------+----------+
    msmf::Row<StateStandby,                        EventConfigure,             OperationalSm,                     msmf::none,       GuardIsEnabledAndWithinCurrentCyclingInterval>,
    msmf::Row<StateStandby,                        EventConfigure,             StateStartWaiting,                 msmf::none,       GuardIsEnabledAndWithinFutureCyclingInterval>,
    msmf::Row<StateStandby,                        EventConfigure,             msmf::none,                        msmf::none,       msmf::none>,
    //        +----------------------------------+-------------------------+---------------------------------+--------------------+----------+
    msmf::Row<StateStartWaiting,                   EventConfigure,             OperationalSm,                     msmf::none,       GuardIsEnabledAndWithinCurrentCyclingInterval>,
    msmf::Row<StateStartWaiting,                   EventConfigure,             msmf::none,                        msmf::none,       GuardIsEnabledAndWithinFutureCyclingInterval>,
    msmf::Row<StateStartWaiting,                   EventConfigure,             StateStandby,                      msmf::none,       msmf::none>,
    msmf::Row<StateStartWaiting,                   EventStartWaitTimerExpired, OperationalSm,                     msmf::none,       msmf::none>,
    //        +----------------------------------+-------------------------+---------------------------------+--------------------+----------+
    msmf::Row<OperationalSm,                       EventConfigure,             msmf::none,                        msmf::none,       GuardIsEnabledAndWithinCurrentCyclingInterval>,
    msmf::Row<OperationalSm,                       EventConfigure,             StateStartWaiting,                 msmf::none,       GuardIsEnabledAndWithinFutureCyclingInterval>,
    msmf::Row<OperationalSm,                       EventConfigure,             StateStandby,                      msmf::none,       msmf::none>,
    msmf::Row<OperationalSm,                       EventCycleTimeout,          msmf::none,                        msmf::none,       GuardIsEnabledAndWithinCurrentCyclingInterval>,
    msmf::Row<OperationalSm,                       EventCycleTimeout,          StateStartWaiting,                 msmf::none,       GuardIsEnabledAndWithinFutureCyclingInterval>,
    msmf::Row<OperationalSm,                       EventCycleTimeout,          StateStandby,                      msmf::none,       msmf::none>
    //        +----------------------------------+-------------------------+---------------------------------+--------------------+----------+
    >, OBJECTS_COUNTER(transition_table) {};


    template<class Fsm, class Event>
    void no_transition(Event const& e, Fsm& rFsm, int state)
    {
        typedef typename Fsm::stt Stt;
        typedef typename msm::back::generate_state_set<Stt>::type all_states; //all states
        std::string state_name;
        // fill state_name for state
        boost::mpl::for_each<all_states,boost::msm::wrap<mpl::placeholders::_1> >
                  (msm::back::get_state_name<Stt>(state_name, state));

         LOG4CXX_INFO(Logger(), "no_transition from state "
                                                         << state_name << " by event "
                                                         << typeid(e).name());
    }

    template <class Fsm, class Event>
    void exception_caught (Event const& event, Fsm& rFsm, const std::exception& e)
    {
        LOG4CXX_ERROR(Logger(), " exception_caught: " << e.what() <<" by event " << typeid(event).name());
    }


}; // OuterSm_

typedef msm::back::state_machine<OuterSm_> OuterSm;
typedef OuterSm::stt Stt;
typedef msm::back::generate_state_set<Stt>::type all_states;

I've created a small unit test just to check that basic transition works with the guard.

int main() {

    /// State machine
    OuterSm sm;
    sm.start();

    
    LOG4CXX_INFO(Logger(), "current state: " << *sm_.current_state());
    auto res = sm.process_event(EventConfigure());
    LOG4CXX_INFO(Logger(), "process result: " << res);
    LOG4CXX_INFO(Logger(), "current state: " << *sm_.current_state());

    return 0;
}

Which output is:

4 [0x7faaa5996380] INFO staticLogger null - StateStandby::on_entry
4 [0x7faaa5996380] INFO mainLogger:0x1000000:0 null - current state: 0
4 [0x7faaa5996380] INFO mainLogger:0x1000000:0 null - process result: 1
4 [0x7faaa5996380] INFO mainLogger:0x1000000:0 null - current state: 0
4 [0x7faaa5996380] INFO staticLogger null - StateStandby::on_exit

Meaning somehow my event was processed but there was no transition actually made from StateStandby to OperationalSm .

I've saw this comment:
Boost MSM only processing internal transitions
But I assume it is not relevant to my case because I've created two tuple of guards (And) which one of them will always return false and other return always true.

Is there something I'm missing here that should be done in order the outerSm to invoke OperationalSm (initial state) and other transitions to work as needed?

I've found out that I created the same issue as in:
Boost MSM only processing internal transitions
By adding redundant (empty) transition into transition_table :

msmf::Row<StateStandby,                        EventConfigure,             msmf::none,                        msmf::none,       msmf::none>,

When I removed it and left with (first part of the OuterSm transition):

msmf::Row<StateStandby,                        EventConfigure,             OperationalSm,                     msmf::none,       GuardIsEnabledAndWithinCurrentCyclingInterval>,
msmf::Row<StateStandby,                        EventConfigure,             StateStartWaiting,                 msmf::none,       GuardIsEnabledAndWithinFutureCyclingInterval>

I see the following output:

4 [0x7faaa5996380] INFO staticLogger null - StateStandby::on_entry
4 [0x7faaa5996380] INFO mainLogger:0x1000000:0 null - current state: 0
4 [0x7fc282a66380] INFO staticLogger null - GuardConfigCanBeUsed
4 [0x7fc282a66380] INFO staticLogger null - GuardWithinFutureCycleInterval
4 [0x7fc282a66380] INFO staticLogger null - GuardConfigCanBeUsed
4 [0x7fc282a66380] INFO staticLogger null - GuardWithinCurrentCycleInterval
4 [0x7fc282a66380] INFO staticLogger null - StateStandby::on_exit
4 [0x7fc282a66380] INFO staticLogger null - Operational::on_entry
4 [0x7fc282a66380] INFO staticLogger null - GettingStats::on_entry

As I was expected to see.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM