# CANopen Examples - [CANopen Examples](#canopen-examples) - [Receive and send PDOs from a QML application](#receive-and-send-pdos-from-a-qml-application) - [Prerequisites](#prerequisites) - [Create a QML project](#create-a-qml-project) - [Create a new CANopen bus](#create-a-new-canopen-bus) - [Add transmit (TX) signal](#add-transmit-tx-signal) - [Add receive (RX) signal](#add-receive-rx-signal) - [Create TX PDO](#create-tx-pdo) - [Create RX PDO](#create-rx-pdo) - [Map signals to PDO](#map-signals-to-pdo) - [Update the project](#update-the-project) - [Display PDO in QML](#display-pdo-in-qml) - [Send PDO value from QML](#send-pdo-value-from-qml) - [Start Fieldbus Access with generated configuration](#start-fieldbus-access-with-generated-configuration) - [Send random PDO data and view in QML](#send-random-pdo-data-and-view-in-qml) - [Send PDO value from QML (continued)](#send-pdo-value-from-qml-continued) - [Display CANopen errors in a list view](#display-canopen-errors-in-a-list-view) - [Show stack status in QML](#show-stack-status-in-qml) - [Test status property with CAN data](#test-status-property-with-can-data) ## Receive and send PDOs from a QML application Using the LinX UX designer we can design and test sending CANopen signals on the virtual CAN bus withing the VM. Following example shows how to create a QML application and update it using LinX Manager Fieldbus Access to send and receive CANopen data on the CAN bus. ### Prerequisites - Data Engine installed on target device. - Fieldbus Access 1.3.0 or greater installed on target device. - Interface `can0` is up. - `can-utils` installed. Data Engine and Fieldbus Access is pre-installed on UX Designer VM 4.0. Newer versions can be downloaded from the support site. ### Create a QML project Create a new project to use through the example. 1. Open Qt Creator. 2. `File` > `New file or Project...`. 3. Select `CrossControl Project` and pick `Qt Quick 2 Application`. 4. Follow the on-screen instructions to finalize the project creation: 1. Display resolution: 800x480 2. Kit: Desktop ### Create a new CANopen bus 1. Open LinX Manager Fieldbus Access from the mode selector (left side). 2. Select the created project from the project selector drop-down menu. 3. Create a new CAN bus by pressing the add button ![Add bus](../../source/icons/LinX_FA_AddBus_mask.png) and select "Add new CANopen slave bus". 4. An empty CANopen bus is created with default settings. ### Add transmit (TX) signal 1. Select "Transmitted Signals" tab from the middle panel. 2. Right mouse click and select "Add new signal". 3. New signal created. 4. Double click the newSignal name and change it to "transmitSignal". | DE Signal | DE Datatype | Gain | Offset | OD Index | OD Subindex | |----------------|-------------|------|--------|----------|-------------| | transmitSignal | INT | 1 | 0 | 2270 | 2 | ### Add receive (RX) signal 1. Select "Received Signals" tab from the middle panel. 2. Right mouse click and select "Add new signal". 3. New signal created. 4. Double click the newSignal name and change it to "receiveSignal". | DE Signal | DE Datatype | Gain | Offset | OD Index | OD Subindex | |---------------|-------------|------|--------|----------|-------------| | receiveSignal | INT | 1 | 0 | 2170 | 2 | ### Create TX PDO 1. Select "TPDO Mapping" tab from the middle panel. 2. Right mouse click and select "Add new PDO". 3. New transmit PDO created. 4. Double click Transmission Type and set to `Asynchronous Manufacture Specific` | PDO Name | COB-ID | Tranmission Type | SYNCs | Inhibit T | Event T | Tot b. | |----------|---------------|----------------------------------------------|-------|-----------|---------|--------| | TPDO_1 | $NODEID+0x180 | Asynchronous Manufacture Specific (Type 254) | | | | 0 | ### Create RX PDO 1. Select "RPDO Mapping" tab from the middle panel. 2. Right mouse click and select "Add new PDO". 3. New receive PDO created. 4. Double click Transmission Type and set to `Asynchronous Manufacture Specific` | PDO Name | COB-ID | Tranmission Type | SYNCs | Inhibit T | Event T | Tot b. | |----------|---------------|----------------------------------------------|-------|-----------|---------|--------| | RPDO_1 | $NODEID+0x200 | Asynchronous Manufacture Specific (Type 254) | | | | 0 | ### Map signals to PDO 1. Select "TPDO Mapping" tab from the middle panel. 2. Add the created signal to the PDO. On the **TPDO_1**, right mouse click and "Add signal". 3. Do the same on "RPDO Mapping" tab. | PDO Name | COB-ID | Tranmission Type | SYNCs | Inhibit T | Event T | Tot b. | |----------------|---------------|----------------------------------------------|-------|-----------|---------|--------| | TPDO_1 | $NODEID+0x180 | Asynchronous Manufacture Specific (Type 254) | | | | 32 | | transmitSignal | 2270 | 2 | INT | | | 32 | ### Update the project With the two PDOs created, the last step to perform with the plugin is to export the configuration and update the active project. 1. From the projector selector, press "Save" for the changes to take effect. 2. Verify that the project was updated by opening the General Messages tab (`Alt+6`): > LinX Manager Data Engine: Project updated successfully. 3. Selected project is now updated with new code and files. See [How-tos](usage) for a complete list of generated files. Snippet from `dataengine.h`: ```cpp class DataEngine : public DataEngineBase { Q_OBJECT // Generated Signal MetaProperties Q_PROPERTY (ShortConsumerSignal* fieldbusAccess_CANopenError_CAN0 READ fieldbusAccess_CANopenError_CAN0 CONSTANT) Q_PROPERTY (ShortConsumerSignal* fieldbusAccess_CANopenStatus_CAN0 READ fieldbusAccess_CANopenStatus_CAN0 CONSTANT) Q_PROPERTY (IntProducerSignal* transmitSignal READ transmitSignal CONSTANT) Q_PROPERTY (IntConsumerSignal* receiveSignal READ receiveSignal CONSTANT) ``` ### Display PDO in QML Values from the CAN-bus can now be visualized directly in the UI using the context property `dataEngine`. The documentation for LinX Manager Data Engine contains further instructions how to use the context property (both from QML and Widget projects). 1. Open `main.qml` with the editor 2. Locate `// add your GUI code below this line` 3. Add the following to display `receiveSignal` in a Text component: ``` qml Text { id: rxSignal_Label anchors.centerIn: parent font.pointSize: 20 color: "white" text: "RX Signal: " } Text { id: rxSignal anchors.left: rxSignal_Label.right anchors.top: rxSignal_Label.top color: dataEngine.receiveSignal.status ? "red" : "white" text: dataEngine.receiveSignal.value } ``` ### Send PDO value from QML The snippet below will create two buttons in QML. When the first is clicked, it will update the TPDO `transmitSignal` and set the value to -50. When the second button is clicked, it will update the same TPDO again and set the value to 100. The value will be visible on the CAN bus when Fieldbus Access is running (future step). 1. Add this snippet beneath the code added in the previous section: ``` qml Rectangle { id: lowTXSignal width: 220; height: 60 anchors.top: rxSignal.bottom anchors.left: rxSignal_Label.left color: btnMouseArea1.pressed ? Qt.darker("grey", 1.5) : "grey" Text { anchors.centerIn: parent text: "Set value low" } MouseArea { id: btnMouseArea1 anchors.fill: parent onClicked: dataEngine.transmitSignal.value = -50 } } Rectangle { id: highTXSignal width: 220; height: 60 anchors.top: lowTXSignal.bottom anchors.left: rxSignal_Label.left color: btnMouseArea2.pressed ? Qt.darker("grey", 1.5) : "grey" Text { anchors.centerIn: parent text: "Set value high" } MouseArea { id: btnMouseArea2 anchors.fill: parent onClicked: dataEngine.transmitSignal.value = 100 } } ``` ### Start Fieldbus Access with generated configuration The application is now prepared to send and receive value from/to the CAN bus. What's left is to run Data Engine and Fieldbus Access to let it handle the CAN-communication. 1. Start Data Engine using the desktop shortcut. 2. Locate the generated configuration file for Fieldbus Access in the project directory. `[project directory]/LinXManager_FieldbusAccess/LinXManager_FA_configfile.json`. 3. Open a terminal and use the command `candump can0` to view the traffic which is sent by Fieldbus Access to the CAN bus. 4. Drag and drop the configuration on the Fieldbus Access shortcut found on the desktop. 5. Fieldbus Access start to execute based on the information found in the configuration. 6. Open a new terminal and use the command `cansend can0 000#0100` to change Fieldbus Access state from `pre-operational` to `operational`. Fieldbus Access will start and send initialization messages to the CAN bus. ``` console ccs@LinX-VM:~$ candump can0 can0 701 [1] 00 can0 081 [8] 00 00 00 00 00 00 00 00 can0 000 [2] 01 00 can0 280 [8] 00 00 00 00 00 00 00 00 can0 380 [8] 00 00 00 00 00 00 00 00 can0 480 [8] 00 00 00 00 00 00 00 00 can0 1A0 [8] 00 00 00 00 00 00 00 00 can0 2A0 [8] 00 00 00 00 00 00 00 00 can0 3A0 [4] 00 00 00 00 can0 4A0 [8] 00 00 00 00 00 00 00 00 can0 1B0 [8] 00 00 00 00 00 00 00 00 can0 2B0 [8] 00 00 00 00 00 00 00 00 can0 3B0 [8] 00 00 00 00 00 00 00 00 can0 4B0 [8] 00 00 00 00 00 00 00 00 can0 1C0 [4] 00 00 00 00 can0 2C0 [8] 00 00 00 00 00 00 00 00 can0 3C0 [8] 00 00 00 00 00 00 00 00 can0 4C0 [8] 00 00 00 00 00 00 00 00 ``` ### Send random PDO data and view in QML With Data Engine and Fieldbus Access running from the previous step, it is now possible to read data from the CAN bus and display the result in the application created earlier. 1. Compile and start the application from Qt Creator. 2. Text field for `receiveSignal` are displayed with the value assigned to zero. 3. Open a terminal and use `cangen` to generate random data for PDO1. ``` console # Send 4 random bytes every second to PDO1 0x201 (OD Index 0x2170) ccs@LinX-VM:~$ cangen can0 -I 201 -L 4 -g 1000 -v can0 201#52.1E.11.6D can0 201#E1.2D.02.56 can0 201#F7.4A.03.4F can0 201#2B.E4.5C.29 ``` 4. Values for `receiveSignal` is updated based on the values sent on the CAN bus. Color of the text is updated from red to white when the status value changes. ### Send PDO value from QML (continued) Pressing any of the two buttons will update `transmitSignal (TPDO 1)` and later sent to the CAN bus by Fieldbus Access. The physical value from the application is scaled with the configured gain and offset before it is visible on the CAN bus. | Physical | Gain | Offset | Raw (hex) | |----------|------|--------|------------| | -50 | 1 | 0 | 0xCEFFFFFF | | 100 | 1 | 0 | 0x64000000 | Use `candump can0` to view the CAN frames sent by Fieldbus Access: ``` console ccs@LinX-VM:~$ candump can0 can0 181 [4] CE FF FF FF # Transmit value -50 can0 2A0 [8] 00 00 00 00 CE FF FF FF can0 181 [4] 64 00 00 00 # Transmit value 100 can0 2A0 [8] 00 00 00 00 64 00 00 00 ``` ## Display CANopen errors in a list view The tool injects the project with a model which stores CANopen stack errors. Information stored in the model can be displayed in QML, for example with a `ListView` or `TableView`. The model is accessed via the context property `canopenStatusModel`. More information of how errors are generated and about CANopen error model can be found on the [Error Handling](error-handling.md) page. Example of a `ListView` in QML which displays four roles from the error model: ``` qml ListView { width: parent.width height: parent.height model: canopenStatusModel delegate: Row { width: parent.width spacing: 25 Text { text: bus } Text { text: type } Text { text: message } Text { text: received } } ``` ### Show stack status in QML The system signal `fieldbusAccess_CANopenStatus_CAN#` receives stack state specific information from the Network Management (NMT). | State | Code (hex) | |-----------------|------------| | Initialisation | 0x00 | | Pre-Operational | 0x04 | | Operational | 0x05 | | Stopped | 0x7F | 1. Open `main.qml` with the editor 2. Add the following to display received status in a Text component: ``` qml Text { anchors.right: parent.right anchors.bottom: parent.bottom color: "#C00" font.pixelSize: 32; text: (dataEngine.fieldbusAccess_CANopenStatus_CAN0.value === FieldbusAccessCANopenStatusModel.NodeStateInitialisation) ? "Initialisation" : (dataEngine.fieldbusAccess_CANopenStatus_CAN0.value === FieldbusAccessCANopenStatusModel.NodeStateStopped) ? "Stopped" : (dataEngine.fieldbusAccess_CANopenStatus_CAN0.value === FieldbusAccessCANopenStatusModel.NodeStateOperational) ? "Operational" : (dataEngine.fieldbusAccess_CANopenStatus_CAN0.value === FieldbusAccessCANopenStatusModel.NodeStatePreOperational) ? "Pre Operational" : "N/A"; } ``` The `state` will change based on the reception of current CANopen stack status from the Fieldbus Access runtime. This is done by comparing the `fieldbusAccess_CANopenStatus_` signal value with `FieldbusAccessCANopenStatusModel.`. CAN0 automatically added if "0" is the interface number selected in the bus settings. Another suitable control that can be used is the `StatusIndicator` QML type. Import `QtQuick.Extras 1.4` to have access to this type. The indicator will be shown in green when the status is in state `Operational` and unlit otherwise. ``` qml import QtQuick.Extras 1.4 StatusIndicator { anchors.centerIn: parent color: "green" active: dataEngine.fieldbusAccess_CANopenStatus_CAN0.value === FieldbusAccessCANopenStatusModel.NodeStateOperational } ``` ### Test status property with CAN data 1. [Start GUI application](#show-stack-status-in-qml) 2. [Start Fieldbus Access with generated configuration](#start-fieldbus-access-with-generated-configuration) 3. The status will quickly go from `Initialisation` to `Pre-Operational`. 4. Send CANopen master `operational` signal. ``` console cansend can0 000#0100 ``` 5. Status will change to `Operational`.