0

I want to share data and access between states as well as the SM as a whole and the client code (i.e. the code outside the SM).

Based on what I've come up with on the net, the best way would be to inherit all states from a base class.

Adding a base class and making all states & the SM to inherit from that is simple, but how can I add the handler to the backend/frontend of the SM as a member of this base class and how can I initialize it?

This sample code compiles, but crashes when accessing the fsmHandler set in the SubState (the SubState would not normally have access to the root fsm)!

Questions:

How can I get access to the root-SM and its data in the submachines deep down the SM-hierarchy?

Q1) How can I solve the run-time error?

Q2) How I pass data from client code (outside the SM) to the SM doesn't feel right! Is there a better way of doing this? Is it thread safe?

Q3) How can I make typedef StateBase_<MyFsm_> StateBase compile.

I would really appreciate if you could provide a working sample. Thanks for your time & help in advance.

The code:

main.cpp

int main()
{    
    std::cout << "Testing boost::msm ..." << std::endl;
    MyFsm fsm;
    fsm.start();

    MyFsm::State1& tempState = fsm.get_state<MyFsm::State1&>();    
    fsm.m_outerSMData=77;
    tempState.m_fsmHandler = &fsm;


    fsm.process_event(Event1());
    fsm.process_event(Event2());
}

myfsm.h

namespace msm = boost::msm;
namespace msmf = boost::msm::front;
namespace mpl = boost::mpl;

struct Event1{};
struct Event2{};

template<class Fsm>
struct StateBase_{
    //StateBase(Fsm *fsm):m_fsm(fsm){}
    StateBase_(){}
    ~StateBase_(){}

    Fsm *m_fsmHandler;
};

//typedef StateBase_<MyFsm_> StateBase;//How can I make this typedef work?

struct MyFsm_ : msmf::state_machine_def<MyFsm_, StateBase_<MyFsm_> >
{
    struct State1 : msmf::state<StateBase_<MyFsm_>>{
        template<class Event, class Fsm> void on_entry(const Event&, Fsm&) const {std::cout << "State1::on_entry()" << std::endl;}
        template<class Event, class Fsm> void on_exit(const Event&, Fsm&) const {std::cout << "State1::on_exit()" << std::endl;}
    };    

    struct State2_ : msmf::state_machine_def<State2_, StateBase_>{
        template<class Event, class Fsm> void on_entry(const Event&, Fsm&) const {std::cout << "State2::on_entry()" << std::endl;}
        template<class Event, class Fsm> void on_exit(const Event&, Fsm&) const {std::cout << "State2::on_exit()" << std::endl;}

        struct SubState21 : msmf::state<StateBase_>{
            template<class Event, class Fsm> 
            void on_entry(const Event&, Fsm&) const {
                std::cout << "SubState21::on_entry()" 
                <<"OuterSMData= "<<m_fsmHandler->m_outerSMData <<std::endl;
            }
            template<class Event, class Fsm> 
            void on_exit(const Event&, Fsm&) const {
                std::cout << "SubState21::on_exit()" << std::endl;
            }
        };
        typedef mpl::vector<SubState21> initial_state;
    };
    typedef msm::back::state_machine<State2_> State2;
   // Set initial state
   typedef State1 initial_state;

   // Transition table
   struct transition_table:mpl::vector<
         msmf::Row < State1, Event1, State2, msmf::none, msmf::none >,
         msmf::Row < State2, Event2, State1, msmf::none, msmf::none >
   >{};

  template<class Event, class Fsm>
   void no_transition(Event const&, Fsm&, int state){
       std::cout<<"no_transiton detected from state: "<< state << std::endl;
   }

   //void setPtr(int data/*MyFsm_ &fsm*/){State1::m_baseData=10;}
   int m_outerSMData=44;
};
// Pick a back-end
typedef msm::back::state_machine<MyFsm_> MyFsm;
qwa
  • 123
  • 10
  • 1
    I don't have answer for Q1 and Q3, but I know one way to achieve Q2. Here is a way https://wandbox.org/permlink/SdlC7nSisYc7wVKG. process_event() is NOT thread safe. You need to lock it. – Takatoshi Kondo Jun 15 '18 at 12:08
  • @Takatoshi Kondo, So you suggest to manually pass the reference to the fsm down the hierarchy one-by-one into each sub-amchine. Thanks, the solution is simple and works; – qwa Jun 17 '18 at 04:27
  • I have slightly modified your code & moved "State2" into a seperate .h file [here](https://wandbox.org/permlink/ikawCMwOj9Iwhd6S). The `rootFsm` handler can be used in State2's submachines with no problem. BUT when used at the point where it is originally set, I get a compiler error!! I made this modification so that calls to the rootFsm would be uniform & look alike. I can use the `Fsm&` BUT I want to know the reason behind this error!!! How can one function call lead to compile errors while the SAME CODE IN THE SAME FILE, but in another place work? Thanks a lot in advance – qwa Jun 17 '18 at 14:53
  • 1
    it’s off topic comment. I’m on vacation now. I cannot answer in two weeks. – Takatoshi Kondo Jun 19 '18 at 06:22
  • 1
    It's because fsm_ and State2__ depend on each other. You can solve it like https://wandbox.org/permlink/hbB405PRxc2FqG8Y – Takatoshi Kondo Jun 29 '18 at 03:03
  • 1
    Or you can simply share your user define data directory instead of sharing the parent state machine. See https://wandbox.org/permlink/qeH4ULy1V5GRllfL – Takatoshi Kondo Jun 30 '18 at 05:40
  • @Takatoshi Kondo, thanks a lot. your code hepled solve my problem. I edited the questions. Pls post your answer so i can mark it as solved. regards – qwa Jul 04 '18 at 12:34
  • I just refer this question again to solve other question. And then I noticed that your comment above. So I added my answer. – Takatoshi Kondo Nov 19 '19 at 02:23

1 Answers1

1

You can access the outer state machine from the sub state. This is the state machine diagram based on your code.

+-------+--------------------------------------------------------+
| Fsm_  |  member variable: m_outerSMData                        |
+-------+                                                        |
|                                                                |
|         *                                                      |
|         |                                                      |
|         V                                                      |
|     +----------+      +-----------------------------------+    |
|     |  State1  |      |      State2                       |    |
|     +----------+Event1+-----------------------------------+    |
|     |          |----->| on_entry/rootFsm=&f               |    |
|     |          |      | member variable: rootFsm          |    |
|     |          |      |  +---------------------------+    |    |
|     |          |Event2|  | SubState21                |    |    |
|     |          |<-----|  |                           |    |    |
|     |          |      |  | on_entry/                 |    |    |
|     |          |      |  | access                    |    |    |
|     |          |      |  | f.rootFsm->m_outerSMData  |    |    |
|     |          |      |  +---------------------------+    |    |
|     +----------+      +-----------------------------------+    |
+----------------------------------------------------------------+

In order to access the outer state machine, State2__ need to have the pointer of MyFsm_. So I added rootFsm as the member variable of State2__ and assigns the pointer of the outer state machine to it at Stete2__::on_entry().

If you want to access the member of the outer state machine at the Stete2__::on_entry(), you need the definition of MyFsm_. So you need to separate the member function State2__::on_entry's decralation and definition.

Here is a key structure to achieve the goal:

struct MyFsm_;         // forward declaration

struct State2__ .... { // class definition

    // member function template declaration
    template<class Event, class Fsm> void on_entry(const Event&, Fsm& f);

    MyFsm_* rootFsm;
};

struct MyFsm_ ... {    // class definition
    // requre State2__ definition here
};

// member function template definition
template<class Event, class Fsm> void State2__::on_entry(const Event&, Fsm& f) {
    // requre MyFsm_ definition here
    rootFsm = &f;
    std::cout << "Print OuterSMData= " << rootFsm->m_outerSMData << std::endl; 
}

Here is the live demo: https://wandbox.org/permlink/hbB405PRxc2FqG8Y

Takatoshi Kondo
  • 3,111
  • 17
  • 36