I have a simple state machine that acts differently depending on whether I define an empty entry program, or don't define an entry program. When I don't define an entry program (but it does have a run program), it appears to get locked into the default entry program and the machine stops responding to events. I know I'm doing _something_ wrong, I'm just not sure what. Sample code attached.
The unit test case is attempting to single step events through the state machine, and verifying the resulting state. I've seen the same locked-in-entry-program behaviour when using slave or periodic activities, when using execute() after each event on a slave activity or not using execute(), and in either mode of the state machine (reactive and automatic). The state machine currently has the entry programs of interest commented out.
Note that the ServoController task has the events goSafe(), goSoftware() and goHardware(), and contains the state machine given below.
Any help appreciated.
Stephen
NB TS_ASSERT() is CxxTest's equivalent of CPPUNIT_ASSERT()
StateMachine ServoController
{
initial state SAFE
{
transition goSoftware() select SOFTWARE
transition goHardware() select HARDWARE
entry { do servocontroller.setSafe() }
}
state SOFTWARE
{
transition goSafe() select SAFE
transition goHardware() select HARDWARE
// entry { }
run { do servoController.softwareServo() }
}
state HARDWARE
{
transition goSafe() select SAFE
transition goSoftware() select SOFTWARE
// entry { }
run { do servoController.hardwareServo() }
}
final state ENDSAFE
{
entry { do servoController.setSafe() }
}
}
RootMachine ServoController servoController
-
- Unit test case of interest **
void test_States()
{
ServoController s("servoController");
MockupServoControllerPeer m("m", NUMDOF);
SlaveActivity as(s.engine());
SlaveActivity am(m.engine());
// PeriodicActivity as(RTT::OS::LowestPriority, 1, s.engine());
// PeriodicActivity am(RTT::OS::LowestPriority, 1, m.engine());
// set properties, connect ports/peers, load state machine, start activities
setupServoTest(s, m, as, am);
StateMachinePtr stateMachine = s.engine()->states()->getStateMachine("servoController");
TS_ASSERT(NULL != stateMachine);
// do one cycle
TS_ASSERT(am.execute());
TS_ASSERT(stateMachine->inInitialState());
TS_ASSERT(stateMachine->inStrictState("SAFE"));
// emit events, cycle, check for state changes
s.goSoftware();
TS_ASSERT(am.execute());
TS_ASSERT(stateMachine->inStrictState("SOFTWARE"));
s.goSafe();
TS_ASSERT(am.execute());
TS_ASSERT(stateMachine->inStrictState("SAFE"));
s.goHardware();
TS_ASSERT(am.execute());
TS_ASSERT(stateMachine->inStrictState("HARDWARE"));
s.goSoftware();
TS_ASSERT(am.execute());
### line 217: fails, the state machine is stuck in the entry program for SOFTWARE
TS_ASSERT(stateMachine->inStrictState("SOFTWARE"));
std::cout << stateMachine->getCurrentStateName() << std::endl;
s.goSafe();
TS_ASSERT(am.execute());
### line 222: fails and event goSafe() is ignored as still stuck in SOFTWARE entry program
TS_ASSERT(stateMachine->inStrictState("SAFE"));
std::cout << stateMachine->getCurrentStateName() << std::endl;
TS_ASSERT(as.stop());
TS_ASSERT(am.stop());
}