4

I'm trying to understand the usage of QStateMachine, specifically handling user events that trigger transitions. Additionally, I want to understand the best way to implement guards. I've drawn a state machine below. It's mostly sequential and not a great example of a state machine, but it would serve the purpose of not blocking since there are delays while waiting for the results of QProcess calls. Those delays are instead handled asynchronously as timeout events.

The state machine assumes no rndis connection at startup, then periodically runs a longer sequence of events to check for a connection. Once a connection is detected, a shorter check is run periodically to make sure we're still connected and if not, goes back to running the longer check.

This is some basic setup code that is incomplete.

// Set up state machine.  Do this so that checking for presence
// is non-blocking.  Delays are handled by framework.
//
QState* detected = new QState();
QState* notDetected = new QState();
QState* waitForIfDown = new QState();
QState* waitForCdcEther = new QState();

QEvent* timeout = new QEvent(QEvent::Type(EVENT_TIMEOUT));

m_machine.addState(detected);
m_machine.addState(notDetected);
m_machine.addState(waitForIfDown);
m_machine.addState(waitForCdcEther);

// Need to subclass QEventTransition and implement virtuals 
// onTransition and eventTest?

detected->addTransition();
notDetected->addTransition();
waitForIfDown->addTransition();
waitForCdcEther->addTransition();

m_machine.setInitialState(notDetected);
m_machine.start();

I can call startTimer on the Detector object, which is where this code exists. Then in the Detector::timerEvent, I can post a user-defined 'timeout' event to the state machine. I also need to start a new timer with each transition. The actions for each transition will occur in a subclass of QEventTransition, presumably in the 'onTransition' method. How do I pass the Detector object to each of these (unique) transition objects so that the Detector is the one calling startTimer()? Also, I'm not sure how to implement the guard conditions on the two transitions that have them. I see the virtual 'eventTest' in QAbstractTransition, but don't quite see how it could be used to implement a guard. I'm pretty sure my thinking is not quite the Qt way, yet.

I've looked at the two books on Qt I could find (from Summerfield and from Ezust) and also at: http://doc.qt.io/qt-5/statemachine-api.html#events-transitions-and-guards. The books make no reference to QStateMachine at all. The Qt online documentation seems to me to lack sufficient example code for general-purpose state machines. It does a good job of showing how to use existing signals to create transitions, but not user-defined events.

Any help is welcome. Thanks.

Simple detection state machine

EDIT: I realize that I could implement my own simple state machine with a basic switch statement in the Detector::timerEvent() function. I'm doing this now, but I am still very interested to understand how this would be done using QStateMachine.

Rich von Lehe
  • 1,362
  • 2
  • 16
  • 38
  • is there a particular reason why you do not want to use Qt messages to trigger transititions and you want to use an event instead ? – Marco May 07 '15 at 08:06
  • @Marco - do you mean signals? No, no reason. The only reason I was looking at events is that QEventTransition has virtuals 'onTransition' and 'eventTest' which seemed like they might be useful for handling transition actions and guard conditions. – Rich von Lehe May 07 '15 at 14:11
  • In my experience of QStateMachine I have always used to messages to trigger transitions, but that does not mean it's the better way it is just that seemed simpler to me. If your QProcess class emits a "detetcted" message or a "non detected" message at each timeout, you will be able to switch from notdetected to detected that way. Then each time you enter a detected or non detected you can start a timer using the onEntry overridden method. I do not know if this makes any sense to you, but if you post somewhere the code I can help more. – Marco May 08 '15 at 12:26
  • Unfortunately, it would be confusing roles of objects to have the QProcess determine if the connection is there. For example, I run a QProcess that executes dhclient locally. The successful running of this process doesn't tell me that I'm connected to anybody, it just tells me that the I ran the process. Further checks (after a prescribed delay) of the dhcp client database files are needed to determine if a connection is made and what the remote's IP address is. – Rich von Lehe May 11 '15 at 16:00
  • Did you ever return to this question with an answer? I'm experiencing a similar problem. – Zimano Jun 27 '17 at 13:42
  • @Zimano - unfortunately, I never came to a definitive solution to that problem using a Qt state machine. If I recall, I ended up handling state outside of Qt entirely, and I imagine it's common to do that unless you have simple transitions. – Rich von Lehe Jun 27 '17 at 17:52

0 Answers0