States#
Role in SysML v2#
A state definition is a kind of action definition that defines the conditions under which other actions can execute. A state usage is a usage of a state definition. State definitions and usages are used to describe state-based behavior, where the execution of any particular state is triggered by events.
State machines can only be added to parts.
Supported features are:
- State machine definition:
state def sm { ... } - Default state:
entry; then statename; - Default state selection, extended form: allows selecting the default state based on conditions.
- States, long form: may have
entry,exit, anddoactions. See OperationalRed{ entry; ... }in the listing. - States, short form: only a name is required.
- Transitions, short form: must immediately follow a state (see
accept after ... then ...in the listing). - Transitions, long form: use the extended form. See transition t1 in the listing.
- History (via naming convention of state names: for shallow history use S1**_H**; for deep history use S1**_HH**)
// definition of events
enum def TRAFFICLIGHTCONTROLLERSM_EVENT_T {
//@TrafficLightController
evOperational;
evError;
}
state def tlcStateMachine {
entry; then OutOfService;
state OutOfService {
entry; then OutOfServiceYellowOn;
state OutOfServiceYellowOn{
entry action setYellowLED{}
}
accept after 0.5[SI::second] then OutOfServiceYellowOff;
state OutOfServiceYellowOff {
entry action resetYellowLED{}
}
accept after 0.5[SI::second] then OutOfServiceYellowOn;
transition t1 first OutOfService
accept TRAFFICLIGHTCONTROLLERSM_EVENT_T::evOperational then Operational;
}
state Operational {
entry; then OperationalRed;
state OperationalRed {
entry action setRedLED{}
exit action resetRedLED{}
}
state OperationalRedYellow {
entry action setRedAndYellowLED{}
exit action resetRedAndYellowLED{}
}
state OperationalGreen {
entry action setGreenLED{}
exit action resetGreenLED{}
}
state OperationalYellow {
entry action setYellowLED{}
exit action resetYellowLED{}
}
transition t1 first OperationalRed accept after 1[SI::second]
then OperationalRedYellow;
transition t2 first OperationalRedYellow accept after 1[SI::second]
then OperationalGreen;
transition t3 first OperationalGreen accept after 1[SI::second]
then OperationalYellow;
transition t4 first OperationalYellow accept after 1[SI::second]
then OperationalRed;
transition t5 first Operational
accept TRAFFICLIGHTCONTROLLERSM_EVENT_T::evError then OutOfService;
}
}The system, including the state machines, is then fully generated following the well-known Sinelabore RT state machine structure.
Defining events#
It is required to use enums to define events to be processed by the state machine.
Add a comment in the enum that starts with //@ followed by the name of the part whose state machine processes the events (see the examples above).
Transition triggered by timeouts#
A great new feature with SysML v2 is the ability to trigger transitions by timeouts. In UML this was also possible, but in a much more limited way.
transition t1 first start state accept after 0.1[SI::second] then next state;At present, time can only be specified in seconds. For other durations, use a value in seconds—for example, 0.001[SI::second] for 1 millisecond. Each part has a TimerManager class by default to manage timeouts. The code generator emits entry code to start the timer when a state is entered and exit code to stop it when the state is left. A timeout event is added to the event list.
Executing a model#
It is possible to execute the model directly in a C++ main function. In most cases, however, you may want to add your own C++ behavior. Then subclass the generated Part classes and implement the
intended business logic and handlers (i.e. methods of the generated part classes). By default, process() and init() methods are generated per part.
If needed, override these two methods and add your own code. Then call the base-class method to ensure
that the part is initialized correctly. Sub-parts must be created in the init method.
Here is an example of a simple main program:
MyTrafficLightSystem tls;
tls.init();
// Start process thread
for(int i = 0; i < 80; i++) {
tls.process();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}Executing model with state machines#
For each state machine, state-handling classes are generated (for details, see section “3.4. Generating C++ Code” in the manual). Set the following parameters in codegen.cfg; otherwise the compiler will fail:
UseEnumBaseTypes=yesUseStdLibrary = yesCallInitializeInCtor = noEnumBaseTypeForEvents = std::int16_t
A state-handling method with the same name as the topmost state def of the part is generated.
For ports and timeouts, a handler method is added to the generated part class. Override this handler in your derived class and forward timeout events or events received on a port to the state machine. An example handler:
void onTimeout(const TLCEvent& e) override{
std::cout << "[MyTrafficLightController] Timeout fired with id="
<< getNameByEvent(e)<< std::endl;
// enqueue event so it can be handled via SysML code
recvPort.receive(ControlPortDataDef{e});
tlcStateMachine();
}