1

I try to use boost::MSM to implement a simple state machine for testing purpose. There are several events which have to be processed in the right order, so i defer the other events, which are currently not allowed. I try to defer the events in the transition table, to have one place to look for it, despite having all states to look, what events they defer.

I tried to change the transition rows to change their priorities, but it didnt help. If i unkomment the anonymous transition from live_got_image to live_wait_for_image, it works as expected, but i want to transition automaticly to repeatedly enter the states live_wait_for_image/live_got_image until the ev_stop_live get sent.

I expect the following output:

entering: fsm_master
entering: not_ready
no transition from state 0 on event struct `anonymous namespace'::ev_stop_live
leaving: not_ready
starting: live_wait_for_image
leaving: live_wait_for_image
starting: live_got_image
leaving: live_got_image
entering: not_ready

but actually i get the following output:

entering: fsm_master
entering: not_ready
no transition from state 0 on event struct `anonymous namespace'::ev_stop_live
leaving: not_ready
starting: live_wait_for_image
leaving: live_wait_for_image
starting: live_got_image
leaving: live_got_image
starting: live_wait_for_image   

I use boost 1.57.0 and MSVC-2013 (VS-12).

Could anybody get me a useful hint?

Georg

Here is the code:

#include <iostream>
// back-end
#include <boost/msm/back/state_machine.hpp>
//front-end
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>

namespace msm = boost::msm;
namespace mpl = boost::mpl;

namespace 
{
    using namespace boost::msm::front;

    // events
    struct ev_start_stop {};
    struct ev_start_live {};
    struct ev_stop_live {};
    struct ev_learn {};
    struct ev_load {};

    struct ev_got_image { int payload;  };

    // front end: define the FSM structure
    struct fsm_master_ : public msm::front::state_machine_def<fsm_master_> {
        typedef int activate_deferred_events;

        template <class Event, class FSM>
        void on_entry(Event const&, FSM&)
        {
            std::cout << "entering: fsm_master" << std::endl;
        }
        template <class Event, class FSM>
        void on_exit(Event const&, FSM&)
        {
            std::cout << "leaving: fsm_master" << std::endl;
        }

        // the fsm states which are not sub state machines
        struct not_ready : public msm::front::state<> {
            template <class Event, class FSM>
            void on_entry(Event const&, FSM&) { std::cout << "entering: not_ready" << std::endl; }
            template <class Event, class FSM>
            void on_exit(Event const&, FSM&) { std::cout << "leaving: not_ready" << std::endl; }
        };

        // The list of FSM states
        struct live_wait_for_image : public msm::front::state<>
        {
            template <class Event, class FSM>
            void on_entry(Event const&, FSM&) { std::cout << "starting: live_wait_for_image" << std::endl; }
            template <class Event, class FSM>
            void on_exit(Event const&, FSM&) { std::cout << "leaving: live_wait_for_image" << std::endl; }
        };

        struct live_got_image : public msm::front::state<>
        {
            // here we got the image and we can check, if we need to react on an external event
            // otherwise transit to wait_for_image and fetch the next image
            template <class Event, class FSM>
            void on_entry(Event const&, FSM&) { std::cout << "starting: live_got_image" << std::endl; }
            template <class Event, class FSM>
            void on_exit(Event const&, FSM&) { std::cout << "leaving: live_got_image" << std::endl; }
        };

        // ---------------------------------------------------
        // initial state: fsm_master_
        typedef not_ready   initial_state;

        typedef fsm_master_ l;
        struct transition_table : mpl::vector<
            //      Start           Event            Next             Action              Guard
            //    +---------------------+----------------+-------------------+-------------------+----------------+
            _row < not_ready,           ev_start_live,   live_wait_for_image                                       >,

            _row < live_wait_for_image, ev_got_image,    live_got_image                                            >,
             Row < live_wait_for_image, ev_stop_live,    none                , Defer             , none            >,

            _row < live_got_image,      none,            live_wait_for_image                                       >,
            _row < live_got_image,      ev_stop_live,    not_ready                                                 >
            //    +---------------------+----------------+-------------------+-------------------+----------------+
        > {};

        // Replaces the default no-transition response.
        template <class FSM, class Event>
        void no_transition(Event const& e, FSM&, int state)
        {
            std::cout << "no transition from state " << state
                << " on event " << typeid(e).name() << std::endl;
        }

    };

    // back-end: fsm_master
    typedef msm::back::state_machine<fsm_master_> fsm_master;
}

void test() {
    fsm_master s;
    s.start();

    s.process_event(ev_stop_live()); // this gets no transitioned

    s.process_event(ev_start_live()); // this one enters live
    s.process_event(ev_stop_live()); // this gets defered   
    s.process_event(ev_got_image()); // this one enters got_image and the stop live should get processed. 

    // now we should be in not ready again, but we are still in live_wait_for_image

}
int main()
{
    test();
    return 0;
}
m.s.
  • 16,063
  • 7
  • 53
  • 88
schorsch_76
  • 794
  • 5
  • 19
  • "I try to defer the events in the transition table, to have one place to look for it, despite having all states to look, what events they defer." - Okay. You lost me. Will read on a bit out of curiosity – sehe Mar 12 '15 at 12:33
  • I refer to this section of the documentation: – schorsch_76 Mar 12 '15 at 12:38
  • http://www.boost.org/doc/libs/1_57_0/libs/msm/doc/HTML/ch03s02.html#d0e577 – schorsch_76 Mar 12 '15 at 12:40
  • We can now defer an event in any transition of the transition table by using as action the predefined msm::front::Defer functor, for example: Row < Empty , play , none , Defer , none > – schorsch_76 Mar 12 '15 at 12:40
  • None of that clarifies what you mean with the sentence I quoted. – sehe Mar 12 '15 at 12:42
  • 1
    I just want to have all defering of events and transition in the table, insted the defering cluttered over the states, with typedef mpl::vector defered_events; I would prefer ti read it in the transition table. – schorsch_76 Mar 12 '15 at 12:46
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/72836/discussion-between-sehe-and-schorsch-76). – sehe Mar 12 '15 at 12:49
  • "If i unkomment the anonymous transition from live_got_image to live_wait_for_image, it works as expected," Which one? There doesn't seem to be such a comment. – sehe Mar 12 '15 at 13:07
  • I mean this row: "_row < live_got_image, none, live_wait_for_image >," when i put // in front of them, the anonypmous transition gets removed and the defered one gets processed, but it seems the anonymous tarnsition has a higher priority, regardless where i put it in the transition table. In the meantime, i tried to defer the message in the state, but it did show the same behaviour. – schorsch_76 Mar 12 '15 at 13:17
  • That's one strange meaning of the word **un** comment that I was previously not aware of :S – sehe Mar 12 '15 at 13:19
  • So. With that line un-un-commented (sic) it does what you want. Can you _demonstrate_ what it is that you need to happen differently? – sehe Mar 12 '15 at 13:45
  • I want this line in the transition table, to reenter the live_wait_for_image state, if in the meantime no ev_stop_live event got defered. – schorsch_76 Mar 12 '15 at 13:58

1 Answers1

1

I got on the mailing list from Christophe, the following answer:


Hi,

I try to use boost::MSM to implement a simple state machine for testing purpose. There are several events which have to be processed in the right order, so i defer the other events, which are currently not allowed. I try to defer the events in the transition table, to have one place to look for it, despite having all states to look, what events they defer.

I tried to change the transition rows to change their priorities, but it didnt help. If i unkomment the anonymous transition from live_got_image to live_wait_for_image, it works as expected, but i want to transition automaticly to repeatedly enter the states live_wait_for_image/live_got_image until the ev_stop_live get sent.

I'm afraid it won't work. According to the UML standard which MSM tries to follow, anonymous transitions have higher priority than deferred events. You could use a guard in the anonymous transition to disable it if you have a deferred event in the queue, for example:

struct OnlyIfNoDeferred
{
    template<class Event, class Fsm, class SourceState, class TargetState>
    bool operator()(Event const &, Fsm & aFsm, SourceState &, TargetState &)
    {
        return aFsm.get_deferred_queue().empty();
    }
};

As we're talking about anonymous transitions, I read "repeatedly", but please be careful not to add another anonymous transition back otherwise you might get into an endless loop of anonymous transitions.

HTH,

Christophe

schorsch_76
  • 794
  • 5
  • 19
  • From the horse's mouth. I had spotted the "anonymous transitions have higher priority than deferred events" but couldn't figure out a workaround – sehe Mar 14 '15 at 18:09