<< to CrossControl homepage

Support & Service Center

Data Engine

Access and browse DataEngines persistent database values


In the LinX Virtual Development Machine you will find an Graphical application called Flamerobin that you could use to access the database file on your CCpilot device.

This could be usefull if you would like to assert current values or use your own firebird dbf implementation.

In VM, start flamerobin

# flamerobin


GUI-application starts!


Flamerobin Graphical User Interface

Add your device server:

Chose Server from menu and “Register server…”

Name: <preferred name of Server>

Hostname: <IPaddress of device>

Port number: <> (leave blank)


Add your database file:

Right click on the new Server Icon and choose “Register existing database”

Display name: <preferred name of database>

Database path: </tmp/fbdb_fs/linx.fdb> 

User name: <SYSDBA>

Password: <cc…>
















Right click on new db icon and connect.

Right click on preferred table and chose “Browse Data”


Browse Signals
























Environment and Versions: 

LinX Virtual Development Machine  >= 2.0.0


Screen cast: Fieldbus Access - easy to use (Long version ~30 min)

This video shows how to use the Fieldbus Access to configure and use fieldbuses with our plug-in in QtCreator. The fieldbuses you can use are J1939 and CANopen and this example shows J1939. The video clip also shows how easy it is to link graphical Qt components (widgets) to these signals, without needing any programming skills.

Screen cast: Fieldbus Access - easy to use (~5 min)

This video shows how to use the Fieldbus Access to configure and use fieldbuses with our plug-in in QtCreator. The fieldbuses you can use are J1939 and CANopen and this example shows J1939. The video clip also shows how easy it is to link graphical Qt components (widgets) to these signals, without needing any programming skills.

Data Engine connection with Qt5 Quick application

In this article, one approach will be presented how signals in the Data Engine can be connected to QML components. Signal values can either be presented in the GUI for a user or be updated through user input with the GUI.

  • Set signal value from GUI (qml) and send the value to the Data Engine
  • Read value from Data Engine and view it in the GUI (qml)

Achieved by:

  • Write a C++ backend to handle communication with Data Engine
  • Class with Q Properties defines the signals 
  • QML-binds to properties in the signal class handler

The following structure will be used for both projects to achieve the previously mentioned goal:

  • Viewer

    • The Viewer is what the user will see and interact with. It is written with QML and property bindings will be used to bind certain component properties. It communicates with the backend parts Data Engine Control or Data Engine Signal.

  • Data Engine Signal

    • Defines the signals which should be used by the application. Signals are created as properties which the Viewer can bind to. The name of the signals must follow a specific pattern for the current implementation. Will be presented further on in the article.

  • Data Engine Control

    • A central piece for this project and the backend. It handles the communication with the Data Engine through the sapcore interface or by receiving data from the observer. It is also responsible to update signals defined as properties in Data Engine Signal.

  • Observer

    • Receives data from the sapcore interface, such as subscribe result or data for updated signals. Pushes the information to the Data Engine Control which then handles the received data. It’s a part of the Data Engine Control.


The visible layer and what the user will interact with. This example includes two projects: one will act the sender and the other as the receiver. A slider component is used to change the values which should be transmitted to the receiver. In total there are five different signals used, each representing a different data type. The selected value range can be increased or decreased, selected values are for demonstration purpose.

A central part of QML is use to bind properties to each other, and this is what we will utilize to set values and read values from the Data Engine.


To send data we will use the signals which are defined in Data Engine Signal for the SignalSender project and use the event “onValueChanged” for each slider to set a value to one of the available signals.

Slider { 
   id: boolSlider value: 0 
   minimumValue: 0 
   maximumValue: 1 
   stepSize: 1 
   onValueChanged: dataEngineSignal.boolValue_OUT = value 

When the event “onValueChanged” is triggered, it will set a value to the property called “boolValue_OUT”, defined in our Data Engine Signal class. By defining the signal name with “_OUT” in the end, we indicate that this signal should be transmitted to the Data Engine. More information will be presented in the Data Engine Signal section.


The second project acts as the receiver of data. The QML code is very similar to the sender but utilize the bindings in a different manner and the names of the signals are also slightly modified.

Text { 
   id: boolValue 
   text: dataEngineSignal.boolValue_IN 
   font.pixelSize: 12 

With the sender project the a value was set to the property “boolValue_OUT”, in this case we bind the property “boolValue_IN” found in Data Engine Signal to the text property of Text in our QML file. When the property value is updated all properties bound to the signal will be updated, in this case a text field. Another difference is that the signal name how has “_IN” at the end of the, this indicates that the signal should be read and no data should be written to it from the GUI. More about this will be presented further on.

Data Engine Signal

This class is used in both projects to define all the signals that should be subscribed, either as producing signals or as consuming, The content of the files are almost identical, but there are differences.  Signals are created as properties with write, read and notify methods by using the macro Q_PROPERTY. The fastest way to define new signals is with code completion. Start type Q_PROPERTY and Qt Creator will suggest completing it; press the tab-key on the keyboard to do so. Then fill in the data type and the name of the signal. Lastly let Qt Creator create all missing methods and variables by right-clicking on property and select Refactor -> Generate Missing Q_PROPERTY Members...

Naming of signals

As mentioned earlier, signal names have been given a specific ending to define if it should be received (consumed) or written to (produce). This is required for this specific example and is used to instruct the Data Engine Control class which settings it should use when subscribing to all the signals defined in the Data Engine Signal class. The actual signal name used for subscription will be without the trailing “_IN/OUT”. Other types are also valid and here is the complete list:

  • _IN – Consumer
  • _OUT – Producer
  • _INOUT – Bidirectional
  • _MANYOUT – Multiple Producers

It is also possible to add “_P” in the end to indicate the signal is persistent, but this is not used in this example.


Five signals are defined as properties and created with the method previously described. Since all the signals should be received to the application, they all have “_IN” added to the end of the signal name. All the signals are then available for binding. Definition and declaration is mainly kept in the .h-file but initial values for the signals are set on the constructor found in the .cpp-file. These values are read during initialization of the GUI.  When a new value is written to one of the signals, the set method will notify the GUI a new value is available and force an update. In this case, it is the Data Engine Control which writes to the signal by using the set method for the signal which needs to be updated.

Q_PROPERTY(bool boolValue_IN READ boolValue_IN WRITE setboolValue_IN NOTIFY boolValue_INChanged)


The same method is used to define the signals which should be sent to the receiver, but with “_OUT” instead of “_IN”. Besides this difference there is an important step in order to make it possible to write new signal values to the Data Engine. When the GUI sets a new value for a property, the associated WRITE method will be called for that property. For example, setboolValue_OUT:

Q_PROPERTY(bool boolValue_OUT READ boolValue_OUT WRITE setboolValue_OUT NOTIFY boolValue_OUTChanged)

In our case for this property, a method called setboolValue_OUT will be called. This method is generated using the refactor function pointed out earlier. It is slightly modified with the introduction of an additional signal emit, sendSignal (value, name), which is used to send a Qt signal to the Data Engine Control which has a slot paired with the emitted signal. http://doc.qt.io/qt-5/signalsandslots.html . Data Engine Control then takes over the request and sends the value if possible.

void setboolValue_OUT(bool arg) 
   if (m_boolValue_OUT != arg) 
      m_boolValue_OUT = arg; 
      emit boolValue_OUTChanged(arg); 
      emit sendSignal(arg, "boolValue"); 

With this solution it is important that the setboolValue method is only called through the GUI. If Data Engine Control would use this method (done when a new value is received) then the incoming value would be sent back to the Data Engine (an echo). This is why “_IN” signals should only be read, and “_OUT” only be set.

Data Engine Control

This part of the backend has the task handle the connection with Data Engine and take care of signals which has been updated.

Similar to the Data Engine Signal class, Control also has a couple of properties which the GUI can access and read. Such as the status of the connection with Data Engine, name of the client, used host name and port number. There are also a few slots which the GUI could use to perform various tasks, but there are not used in this example.

When the application starts, three methods will be called from main.cpp to Data Engine Control to initialize it:

dataEngineContext.InitConnection("localhost", 0x1235, "Receiver-GUI");
  • Firstly, the connection needs to have the correct settings: where the Data Engine is running, on which port and what the client should call itself. Once these values have been set, the method will attempt to connect to the Data Engine using the provided information.
  • Secondly the Data Engine Control needs a handle to the signals defined in Data Engine Signal. This is a requirement to pass incoming data to the correct property.
  • Lastly, it will try to subscribe to the signals found by the handle. What the code does is that it lists all the properties found through the handle, and for each one of them a series of steps are taken do determine the name of the signal, data type, direction… before it is finally used for a subscription.


Signal updates are received from the Observer which is a part of the Data Engine Control. Once a new value arrives, the ID will be checked in one of the used dictionaries to find the corresponding signal name. Once found, it will use the signal handle previously set during the initialization to update the correct property in Data Engine Signal. The property is updated using the WRITE method associated to the signal, which will trigger the GUI to read the new value thanks to the notify signal.


When Data Engine Signals emits the signal to send data, the slot connected to the signal will be activated, in this case sendToServer(value,name). The method needs to get the ID associated with the name of the signal, this is done by reading the name paired with the key value ID. Once the ID is known, it is just a matter to set the value using the SAP method SetValue(id,value) available in the sapcore-library.


The observer is a part of the Data Engine Control class and will handle signal updates. When it receives a new value for one of the subscribed signals, it will notify the Data Engine Signal class by emitting a signal to one of the associated slots available in the Data Engine Control class (one for each data type). After this, it is up to the Data Engine Control and the slot method to process the received information and act accordingly. 

Flowcharts and structure

Binary Data Project files9.79 KB

Template in CoDeSys for easy DataEngine access

CoDeSys Templates for Data Engine connections

Add below files from the CoDeSys_Data_Engine_Template archive to your CoDeSys Template directory e.g.
[CoDeSys-Path]\3S CoDeSys [Version]\CoDeSys\Templates\


The template is then available when you start a new project
from your CoDeSys IDE.
Environment and Versions: 

CoDeSys 3.5.4.x

Data Engine 2.0.9


Package icon CoDeSys_DataEngine_Template.zip67.23 KB

Data Engine access from CoDeSys

To connect your CoDeSys application to Data Engine, the CCSAP library must be installed from CoDeSys _linx_sdk.projectarchive in your IDE.

The included example at the bottom of this page is default compiled for an arm (XA/XS/VC) device. To be able to run on x86 (XM/XM2) you need to change the device descriptor file in the project accordingly.

Add the following code to your application (see the included CoDeSys_DataEngine_Example):

// SAP DataEngine Connection and Signal Setup //
IF connect THEN
	// Connect to DataEngineServer
	// Submit our clientName and ip address with 
	// port to the device running Data Engine
	sapConnect ( name:='t_CoDeSys', 
	// Subscribe to sync signal
	// Syncsignals swaps between 1 and 0 every 
	// 1s indicating an alive connection.
	sapSubscribe ( name := clientName, 
            dataType := DATATYPE_SYNC, 
            signalType := SIGNAL_CONSUMER,
            persist := FALSE,
            valuePointer := ADR (CoDeSys) );
	// Subscribe to boolean "signal1" as consumer. 
	// Value not stored in dB. Add value to our 
	//Global Variable (SAP_Variables) signal1.	
	sapSubscribe ( name := 'signal1',
            dataType := DATATYPE_BOOL,
            signalType := SIGNAL_CONSUMER,
            persist := FALSE,
            valuePointer := ADR ( signal1 ) );
	// Subscribe to char variable "signal2" as one 
	// of many producer.
	// Value not stored in dB. Add value to our 
	// Global Variable (SAP_Variables) signal2.				 
	sapSubscribe ( name:='signal2',
            dataType := DATATYPE_CHAR,
            signalType := SIGNAL_MANYPRODUCER,
            persist := FALSE,
            valuePointer := ADR (signal2) );
	connect := FALSE;
IF disconnect THEN
	sapDisconnect ();
	disconnect := FALSE;
	//CoDeSys := 0;
After this initialisation, you can access the different signals as normal variables. Any updates in the Data Engine will directly change the variable value, and any change of the variables will be transmitted to the data engine. Example:
signal2 := BOOL_TO_DINT(signal1)*2+CoDeSys*3;
Environment and Versions: 

CoDeSys Version 3.5.x and higher
Data Engine Version 2.0.9 and higher