This project provides a generator for conneting the YAKINDU Statecharttools with a Qt application. Since the concept of incoming and outgoing events is similar to the Qt signal and slot concept it is logical to link both together. Note that the generated code is an Addon onto the already generated C++-Code from SCT. So you need two sgen-files. One to generate the C++ statemachine and one to generate the link layer between the statemachine and your Qt application.
You can decide between a snapshot or a release build. In your YAKINDU SCT Eclipse environment you only need to add the update site you want:
- Snapshot: https://sourceforge.net/projects/sctqtgen/files/repositories/snapshot/
- Release https://sourceforge.net/projects/sctqtgen/files/repositories/release/
If there are any updates you get informed if you select the menu item "Help -> Check for Updates..."
To create a Qt-layer you have to create a new SCT-sgen-file.
- Select "File -> New -> Other..."
- In the wizard you search for "Code Generator".
- Select "YAKINDU SCT -> Code Generator Model"
- Choose an appropriate name and click "Next >"
- Select "Qt-Generator for SCT" from the combobox, choose your statemachine for your Qt layer and click "Finish"
You now have a preconfigured sgen file for your Qt layer. There are two features: Outlet and QtSettings. It is useful to configure the Outlet in the same way as your C++ sgen file. With the QtSettings you can configure the Qt generator.
There are five preconfigured feature parameters to control the Qt generator.
Look at your generated header file of your C++ generated statemachine. The base class name ist equal to the class name of this statemachine. It is equal to the moduleName you configured for your C++ sgen file in the IdentifierSettings feature.
This is the class name of the Qt link layer class. Choose something unique.
You can choose C++11 for generating some additional keywords like override. If you use C++11 don't forget to add the following line to your Qt's .pro-file:
CONFIG += c++11
For the use of the SCT timer interface it is possible to generate a Qt timer implementation. If you need more than one Qt link layer only one implementation of the timer interface is necessary. So set this one to true only in one sgen file.
The generated SCT statemachine is not thread safe as is. If you need to have a thread safe environment you have to set this value to true. Note that Qt mostly makes use of threads so you should set this to true just in case you make use of timers.
Note: You have also set the cpp11 parameter to true because the generator makes use of the C++11 mutexes!
Until version 1.1.1 the generator places some qDebug() calls into the generated code to make debugging easier. Now this is done using the
virtual void sctQtDebug(const QString &message) const;
callback. So you can overload this method for some appropriate logging.
Additionally you can turn off generating the log calls for release builds. The default logging method is generated anyway so there is no need to adjust your overloaded code.
The header contains the
#define QT_SCT_DEBUG 1
definition in the case if this debug flag is true.
If this flags is true the signal and slot names are camel case which is the default. Otherwise the names are generates as lower camel case like Qt is using.
The generated code implements the following methods of the statemachines base class:
- Initialisation of all SCT operation callbacks (so called OCB).
- A pure virtual method initializeValues() for custom value initialisation.
- In events as Qt slots
- Out events as Qt signals
- Respects internal events with an extra runCycle() call.
- Implementation of the TimerInterface
- Implementation of all SCT operations
To setup a new Qt-Project with YAKINDU SCT you should first create a Qt project with qtcreator. After setting up the GUI etc. you can start modelling the statechart using the YAKINDU statechart tools. It's no problem to use qtcreator and YANKINDU SCT on the same project directory at the same time. After that, you have to setup the sgen file for C++ and the Qt-Generator. The C++ feature IdentifierSettings parameter moduleName should have the same name as the Qt feature QtSettings parameter baseClassName.
NOTE! In the default configuration of the C++ generator the operations and variables of the internal scope are not visible. IMO it is a bug and I filed it up. The SCT developers stated out that this bahaviour is by design. If you want to use the internal scope inside your Qt layer you can work aound this by setting the feature GeneratorOptions parameter innerFunctionVisibility to protected as mentioned in the bug.
After setting up the statechart and the sgen files, the YAKINDU SCT and the Qt-Generator plugins have generated the source files.
NOTE! You should add the generated source files to your SCM, since there is no known way to generate them without starting the Eclipse IDE. Watch out for the SCT bugs itemisCREATE/statecharts#273 and itemisCREATE/statecharts#162.
After that you should add the generated files into your Qt project. Select the project's context menu and select "Add existing Files...".
Add a new C++ class which derive the abstract class generated from the Qt generator. Implement this by deriving the base class with public visibility otherwise you cannot connect the Qt's signals and slots to the statemachine. Since the generated class does not implement any operation you have to do this inside this class. Implement also the initializeValues() method since it is defined pure virtual.
First add a member variable of your statemachine's class to the MainWindow class. After that you should expand the constructor:
- Wire all out events as signal from the statemachine to where ever you want.
- Call the statemachine's start() method. Inside this method it calls the SCT init() method to initialize all values from the SCT statemachine. After that the Qt layers *initializeValues() *method is called. Finally the statemachine enters the processing by calling the SCT enter() method. Since the enter() method may raise out events, the react() method of the Qt layer is called.
- Wire all signals from outside to slots of the statemachine which represents the in events. Wiring the signals and slots in this order ensures no loss of events.
Finally you should add a call to the statemachines stop() method to the destructor. Inside the stop() method the SCT's exit() method is called and final out events are processed via the react() method of the Qt layer.
Now basically everything is done to integrate the Qt layer of the SCT statemachine to your Qt application.
First you have to be familiar using the YAKINDU SCT's C++ generator and their implementation notes.
To process one cycle of the SCT's statemachine you have to call it's runCycle() method. The Qt layer overrides this method to additionally call the method react(). This method process all raised out events. Every raised out event will emit a Qt signal. You are free to override the react() method for additional custom processing, but don't forget to call the base classes react() method otherwise you may loose events.
The SCT's in events are implemented as Qt slots inside the Qt layer. In the generated class the slot methods runs the SCT's runCycle() method. Since this method may raise out events the react() method is called internally.
The SCT only supports some very basic native datatypes such as integer and boolean. If you need more typed datatypes like unsigned or slots with more than one parameter you have to apply a custom handler.
For every in event you have to implement the Qt slot. Inside this method call the SCT's raiseXXX() method to inform the statechart. After that you have to call runCycle().
For custom out event processing you have to override the react() method. Emit signals everytime a isRaisedXXX() method returns true.
NOTE! Don't forget to call the base classes react() method otherwise you will loose events.
Since version 1.2.6 the SCT-Qt-Generator automatically supports the new event queue feature of YAKINDU statechart tools.
Under normal circumstances you don't bother about thread safety. Simply modify the feature QtSettings parameter threadSafe to your needs and everything is done. If you need to implement custom processing for events and thread safety you have to add the following line to every custom event handler:
sc_lock lock(mutex);
Stay tuned for some example projects.