Personal tools

Difference between revisions of "VisionSOM-STM32MP1 simple swipe demo"

From SomLabs Wiki

Jump to: navigation, search
 
Line 6: Line 6:
 
[[File:swipedemo_page1.jpg|400px]] [[File:swipedemo_page2.jpg|400px]]
 
[[File:swipedemo_page1.jpg|400px]] [[File:swipedemo_page2.jpg|400px]]
 
</span>
 
</span>
 +
 +
== OpenSTLinux configuration ==
 +
 +
This example requires the qtcharts module to be included during system build. It may be added to the recipes-st/images/st-image-weston.bbappend file in the meta-somlabs layer.
 +
 +
<pre>
 +
inherit populate_sdk_qt5
 +
 +
IMAGE_INSTALL += " \
 +
    qtbase-dev \
 +
    qtbase-mkspecs \
 +
    qtbase-tools \
 +
    qtdeclarative-qmlplugins \
 +
    qtquickcontrols2-qmlplugins \
 +
    qtwayland \
 +
    gstreamer1.0 \
 +
    gstreamer1.0-plugins-good \
 +
    qtcharts \
 +
"
 +
</pre>
 +
  
 
== GUI implementation ==
 
== GUI implementation ==

Latest revision as of 13:37, 9 April 2021

VisionSOM-STM32MP1 simple swipe demo


This project is a simple demo presenting the Qt application with swipe view and line chart. It was tested on the VisionSOM-STM32MP1 module with VisionCB-STM32MP1-STD and the SL-TFT7-TP-800-480-P RGB display. All project files man be downloaded here: SwipeDemo.zip.

Swipedemo page1.jpg Swipedemo page2.jpg

OpenSTLinux configuration

This example requires the qtcharts module to be included during system build. It may be added to the recipes-st/images/st-image-weston.bbappend file in the meta-somlabs layer.

inherit populate_sdk_qt5

IMAGE_INSTALL += " \
    qtbase-dev \
    qtbase-mkspecs \
    qtbase-tools \
    qtdeclarative-qmlplugins \
    qtquickcontrols2-qmlplugins \
    qtwayland \
    gstreamer1.0 \
    gstreamer1.0-plugins-good \
    qtcharts \
"


GUI implementation

The GUI is implemented in the three files described below. The main GUI file: main.qml, defines the application window with two pages. It also contains the implementation of necessary functions that are separated from the ui.qml files.

import QtQuick 2.9
import QtQuick.Controls 2.2

ApplicationWindow {
    visible: true
    visibility: "FullScreen"
    title: qsTr("Tabs")

    SwipeView {
        id: swipeView
        anchors.fill: parent
        currentIndex: tabBar.currentIndex

        Page1Form {
            button.onCheckedChanged: ledHandler.setEnabled(button.checked)
            slider.onValueChanged: ledHandler.setBrightness(slider.value)
        }

        Page2Form {
            id: chartPage
            Connections {
                target: pointGenerator
                onDoAddSample: {
                    chartPage.addPoint(value)
                }
            }

            function addPoint(value) {
                dataSeries.append(numberOfPoints, value)

                if (dataSeries.count > maxNumberOfPoints) {
                    dataSeries.remove(0)
                }

                dataSeries.xAxis.min += 1
                dataSeries.xAxis.max += 1
                numberOfPoints += 1
            }
        }
    }

    footer: TabBar {
        id: tabBar
        currentIndex: swipeView.currentIndex

        TabButton {
            text: qsTr("Page 1")
        }
        TabButton {
            text: qsTr("Page 2")
        }
    }
}

The Page1Form.ui.qml file contains the first application page description. It defines a checkable button and a slited. Both for LEDs controlling.

import QtQuick 2.9
import QtQuick.Controls 2.2

Page {
    property alias button: button
    property alias slider: slider

    header: Label {
        text: qsTr("Page 1")
        font.pixelSize: Qt.application.font.pixelSize * 2
        padding: 10
    }

    Button {
        id: button
        y: 110
        width: 120
        height: 60
        text: qsTr("LED")
        anchors.left: parent.left
        anchors.leftMargin: 100
        anchors.verticalCenter: parent.verticalCenter
        checkable: true
    }

    Slider {
        id: slider
        x: 260
        y: 110
        width: 300
        anchors.right: parent.right
        anchors.rightMargin: 100
        anchors.verticalCenterOffset: 0
        anchors.verticalCenter: parent.verticalCenter
        from: 0
        to: 100
        stepSize: 10
        value: 0
    }
}

The Page2Form.ui.qml file contains the second application page description. It defines a ChartView with a line chart and two axes. The line chart has maximum of 100 points. The function responsible for dynamic points adding is implemented in the main.qml file.

import QtQuick 2.9
import QtQuick.Controls 2.2
import QtCharts 2.0

ChartView {
    antialiasing: true
    animationOptions: ChartView.NoAnimation

    property int numberOfPoints: 0
    property int maxNumberOfPoints: 100
    property alias dataSeries: dataSeries

    LineSeries {
        id: dataSeries
        name: "Values"
        useOpenGL: true

        property alias xAxis: xAxis

        axisX: ValueAxis {
            id: xAxis
            min: -1 * maxNumberOfPoints
            max: 0
            visible: false
        }
        axisY: ValueAxis {
            min: 0
            max: 100
        }
    }
}

Application logic

The project contains the LedHandler class responsible for handling the events generated by the button and slider. It simply uses /sys/class/leds filed for brightness control.

#ifndef LEDHANDLER_H
#define LEDHANDLER_H

#include <QObject>
#include <QFile>

class LedHandler : public QObject
{
    Q_OBJECT
public:
    explicit LedHandler(QObject *parent = nullptr);

signals:

public slots:
    void setEnabled(bool enabled);
    void setBrightness(unsigned int brightness);

private:
    QFile* gpioLedFile;
    QFile* pwmLedFile;
};

#endif // LEDHANDLER_H
#include "ledhandler.h"
#include <QDebug>

LedHandler::LedHandler(QObject *parent) : QObject(parent)
{
    this->gpioLedFile = new QFile("/sys/class/leds/led3/brightness");
    this->gpioLedFile->open(QIODevice::WriteOnly);
    this->pwmLedFile = new QFile("/sys/class/leds/led2/brightness");
    this->pwmLedFile->open(QIODevice::WriteOnly);
}

void LedHandler::setEnabled(bool enabled)
{
    qDebug() << "Enabled" << enabled;

    if (enabled)
        this->gpioLedFile->write("1");
    else
        this->gpioLedFile->write("0");

    this->gpioLedFile->flush();
}

void LedHandler::setBrightness(unsigned int brightness)
{
    qDebug() << "Brightness" << brightness;
    this->pwmLedFile->write(QString::number(brightness).toLatin1());
    this->pwmLedFile->flush();
}

The second class added in this project is the PointGenerator class. It simply uses a QTimer for sending a signal to the chart every one second.

#ifndef POINTGENERATOR_H
#define POINTGENERATOR_H

#include <QObject>
#include <QTimer>

class PointGenerator : public QObject
{
    Q_OBJECT
public:
    explicit PointGenerator(QObject *parent = nullptr);

signals:
    void doAddSample(int value);

public slots:
    void timeout();

private:
    QTimer* timer;
};

#endif // POINTGENERATOR_H
#include "pointgenerator.h"
#include <QDateTime>

PointGenerator::PointGenerator(QObject *parent) : QObject(parent)
{
    this->timer = new QTimer();
    this->timer->setSingleShot(false);
    this->timer->start(1000);
    connect(this->timer, SIGNAL(timeout()), this, SLOT(timeout()));

    qsrand(QDateTime::currentMSecsSinceEpoch() / 1000);
}

void PointGenerator::timeout()
{
    emit this->doAddSample(qrand() % 100);
}

Finally the main.cpp file contains the main application function that creates the application and connects the necessary objects with the GUI.

#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "ledhandler.h"
#include "pointgenerator.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QApplication app(argc, argv);

    LedHandler ledHandler;
    ledHandler.setBrightness(0);
    ledHandler.setEnabled(false);

    PointGenerator pointGenerator;

    QQmlApplicationEngine engine;

    engine.rootContext()->setContextProperty("ledHandler", &ledHandler);
    engine.rootContext()->setContextProperty("pointGenerator", &pointGenerator);

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}
NXP Partner ST Partner Renesas Partner