
LS, I've implemented a state machine (synchronous) with a couple of states and their events. Its purpose is to implement an USDT CAN stack. Because the lower level driver (made that too) passes the incoming CAN messages through a callback function I needed to derive one state in the state machine from: a) the expected boost state base b) my own interface which handles the callback for new messages (observer) The state machine is performing well with one exception, hence this email. The callback function is a member of a struct which is derived from a & b and it is called by the CAN driver. But then when I want to notify the state that the machine is currently in with a post_event this event seems to be discarded even though it should react on it (the machine state has transitions defined for this event and the current state is that state). I also tried using the transit call but that doesn't do anything either. It is just this one member-function that is the problem and before rewriting the state-machine to an asynchronous state machine I wanted to consult some other users. Regards, Iwan Sanders

But then when I want to notify the state that the machine is currently in with a post_event this event seems to be discarded even though it should react on it (the machine state has transitions defined for this event and the current state is that state). I also tried using the transit call but that doesn't do anything either.
Do you try to post_event from a state constructor? How is this state defined exaclty?

Hi thanks for looking into the issue (which is driving me nuts)
I've defines the following Receiving state:
namespace sc = boost::statechart;
namespace mpl = boost::mpl;
struct EvNewFrame : sc::event< EvNewFrame > {};
struct EvNeedFlowControl : sc::event< EvNeedFlowControl > {};
struct EvDoneReceiving : sc::event<EvDoneReceiving> {};
struct Idle_Receiving;
struct ParseFrame;
struct Receiving : ICANMonitorClient, sc::state< Receiving, USDTTransmitter,
Idle_Receiving >
{
typedef mpl::list<
sc::custom_reaction< EvAbort >,
//sc::deferral< EvNewFrame >,
sc::transition< EvNewFrame, ParseFrame >,
sc::transition< EvDoneReceiving , Finished> > reactions;
Receiving( my_context ctx );
~Receiving();
sc::result react( const EvAbort& );
*virtual void UpdateNewCANMessage(CANMessageId pMsgFilter, TT_CANMsg*
pMsg);*
TT_CANMsg* newCANMessage;
std::vector<_u8> wb;
bool DoneReceiving;
};
The UpdateNewCANMessage is a callback function defined in the
ICANMonitorClient interface. This method is being called when new data
frames arrive (that works) but then I want to notify the state machine to
proceed to its next state effectively by sending an EvNewFrame event but
nothing happens.
I tried this->post_event( EvNewFrame() ); // no effect
and this->post_event( boost::intrusive_ptr<EvNewFrame>( new EvNewFrame( ) )
); // no effect
(this->terminate() still works in this method on the other hand)
Regards
On Wed, Mar 25, 2009 at 15:15, Igor R
But then when I want to notify the state that the machine is currently in with a post_event this event seems to be discarded even though it should react on it (the machine state has transitions defined for this event and the current state is that state). I also tried using the transit call but that doesn't do anything either.
Do you try to post_event from a state constructor? How is this state defined exaclty? _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

Hi Iwan [snip]
I tried this->post_event( EvNewFrame() ); // no effect and this->post_event( boost::intrusive_ptr<EvNewFrame>( new EvNewFrame( ) ) ); // no effect
post_event is intended to be called only from within a react member function or an entry-, exit- or transition action. The documentation isn't terribly clear on this but it does say that calling post_event only pushes the event into the queue. That is, post_event does *not* process the event, which is why you don't see the expected transition. I'm wondering whether it wouldn't be *much* easier to simply pack the TT_CANMsg into an event and then let the state_machine process that event? Regards, -- Andreas Huber When replying by private email, please remove the words spam and trap from the address shown in the header.

I guessed that was the problem indeed I followed the event go pushed into the event queue but it miraculously disappears somewhere very strange. If I would make an event which encapsulates the message I would still need to send it from another thread and then I could only use the statemachine.process_event( EvEvent() ) mechanism. I tried that and the behavior was not exactly what I needed. The calling function would not leave the process_event method and hold op the system. Maybe I should start thinking about rewriting the code to use the asynchronous_state_machine. On Wed, Mar 25, 2009 at 16:13, Andreas Huber < ahd6974-spamboostorgtrap@yahoo.com> wrote:
Hi Iwan
[snip]
I tried this->post_event( EvNewFrame() ); // no effect and this->post_event( boost::intrusive_ptr<EvNewFrame>( new EvNewFrame( ) ) ); // no effect
post_event is intended to be called only from within a react member function or an entry-, exit- or transition action. The documentation isn't terribly clear on this but it does say that calling post_event only pushes the event into the queue. That is, post_event does *not* process the event, which is why you don't see the expected transition.
I'm wondering whether it wouldn't be *much* easier to simply pack the TT_CANMsg into an event and then let the state_machine process that event?
Regards,
-- Andreas Huber
When replying by private email, please remove the words spam and trap from the address shown in the header.
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

I guessed that was the problem indeed I followed the event go pushed into the event queue but it miraculously disappears somewhere very strange.
It doesn't disappear. It's simply held in the internal queue until you call process_event() the next time. However, as I said before it's not a good idea to use post_event this way.
If I would make an event which encapsulates the message I would still need to send it from another thread and then I could only use the statemachine.process_event( EvEvent() ) mechanism. I tried that and the behavior was not exactly what I needed. The calling function would not leave the process_event method and hold op the system.
state_machine is not thread-safe and, more importantly, not reentrant, as documented here: http://www.boost.org/doc/libs/1_38_0/libs/statechart/doc/tutorial.html#Async... So both of the approaches you tried are dangerous, to say the least.
Maybe I should start thinking about rewriting the code to use the asynchronous_state_machine.
Yes, that sounds like a good idea. The usage of asynchronous_state_machine is very different from the one of state_machine, so don't hesitate to post here if you run into any problems. HTH, -- Andreas Huber When replying by private email, please remove the words spam and trap from the address shown in the header.

The UpdateNewCANMessage is a callback function defined in the ICANMonitorClient interface. This method is being called when new data frames arrive (that works) but then I want to notify the state machine to proceed to its next state effectively by sending an EvNewFrame event but nothing happens.
I tried this->post_event( EvNewFrame() ); // no effect and this->post_event( boost::intrusive_ptr<EvNewFrame>( new EvNewFrame( ) ) ); // no effect
First of all, before calling post_event, you can try and print-out current states info (see StateChart tutorial). Besides, you can step into post_event in order to see what happens to that event. Just one little doubt: don't you try to post_event asynchronously to a regular state_machine? I.e. isn't UpdateNewCANMessage called from another thread? If so, it's not safe, as you can't be sure what exactly happens to the state_machine in that moment.

I've been printing the states and the "current" state seems to be the
expected one. On the otherhand the callback function is indeed being called
asynchronously (but I now for sure that is only fires in that state because
subscription only happens there).
If I would rewrite the code to use the asynchronous_state_machine I could
fire events through the fifo_scheduler and the problem would be solved?
On Wed, Mar 25, 2009 at 16:19, Igor R
The UpdateNewCANMessage is a callback function defined in the ICANMonitorClient interface. This method is being called when new data frames arrive (that works) but then I want to notify the state machine to proceed to its next state effectively by sending an EvNewFrame event but nothing happens.
I tried this->post_event( EvNewFrame() ); // no effect and this->post_event( boost::intrusive_ptr<EvNewFrame>( new EvNewFrame( ) ) ); // no effect
First of all, before calling post_event, you can try and print-out current states info (see StateChart tutorial). Besides, you can step into post_event in order to see what happens to that event. Just one little doubt: don't you try to post_event asynchronously to a regular state_machine? I.e. isn't UpdateNewCANMessage called from another thread? If so, it's not safe, as you can't be sure what exactly happens to the state_machine in that moment. _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
participants (3)
-
Andreas Huber
-
Igor R
-
Iwan Sanders