Yocto Project for iMX6ULL Part 3: Adding a QT5 application and launch at startup.
Charles Dias, M.Sc.
Embedded Software Engineer | M.Sc in Electrical Engineering | C, Modern C++ | IoT | RTOS | Embedded Linux | Yocto Project
Welcome back to our Yocto Project series!
In this exciting installment, we're diving into creating a recipe to build and install a QT5 application. This process involves fetching content directly from GitHub and seamlessly integrating the built artifacts into the Linux image. Additionally, I'll show you how to set up a recipe that automatically launches your QT5 application at startup.
We're also addressing a common issue with the default image: touch calibration. We'll develop a recipe that initiates the touch calibrator during the first boot. Lastly, we'll enhance the user interface by creating a bbappend file to remove the Weston toolbar, giving it a more polished and professional appearance.
Let's dive into these enhancements!
For those interested, the material used in this series of articles is available in the project's GitHub repository.
Other articles related to the iMX6ULL module
Hardware requirements
I'll use the following hardware configuration:
Adding a Qt application to the Linux image
First, let's create a folder within the meta-article layer specifically for housing our software application recipes. Inside this, we'll add another folder dedicated to our Qt5 application.
Here's how to set it up:
$ mkdir -p layers/meta-article/recipes-software/custom-qt-app
Now, you can head over to the custom-qt-app folder you've created and make a file named custom-qt-app_1.0.0.bb.
$ touch layers/meta-article/recipes-software/custom-qt-app/custom-qt-app_1.0.0.bb
Insert the following content into this file:
SUMMARY = "Recipe for a QT5 application"
DESCRIPTION = "Recipe created to build the QT5 application"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
SRC_URI = "git://github.com/CharlesDias/Qt-on-iMX6ULL.git;branch=main;protocol=https"
PV = "1.0+git${SRCPV}"
SRCREV = "8646e916f66f0f3a951c0c31f50545f5ab4598aa"
DEPENDS += " qtbase libgpiod "
S = "${WORKDIR}/git/samples/Part2-DemoProject"
do_install:append() {
# Install the application
install -d ${D}/opt/DemoProject/bin/
install -m 0755 DemoProject ${D}/opt/DemoProject/bin/
}
FILES:${PN} += "/opt/DemoProject/bin/DemoProject"
# Inherit the qmake5 class to build the application
inherit qmake5
Let's break down the recipe:
To include this recipe in our reference image tdx-reference-multimedia-image, add the following line to the tdx-reference-multimedia-image.bbappend file:
IMAGE_INSTALL += " custom-qt-app "
Note: Create the layers/meta-article/recipes-images/images/tdx-reference-multimedia-image.bbappend file if it doesn't exist. Just to remind you, the path and filename must match the original recipe.
Now, initiate the build process:
$ bitbake tdx-reference-multimedia-image
Once the build is complete, navigate to the build folder and extract the Colibri-iMX6ULL_Reference-Multimedia-Image-upstream-Tezi_6.4.0-devel-<build-date>.tar file. Within the extracted folder, find and extract the Reference-Multimedia-Image-upstream-colibri-imx6ull.tar.xz file. Take a look at the /opt/DemoProject/bin folder to find the DemoProject binary.
You can now install this image onto the Aster board. See the details in the Yocto Project for iMX6ULL Part 0: Concepts, Setting up, and Building.
When the installation process is finished, you can go ahead and access the /opt/DemoProject/bin folder and start manually the Qt application DemoProject.
But hold on! We want the Qt application to launch automatically after boot. Right? Let's achieve this by adding another recipe in the next section.
Adding a service to launch the application
One common requirement in embedded systems is launching an application automatically upon system boot. This section will craft a recipe to configure a systemd service to start our Qt application at startup.
Do you remember that the reference image automatically launches the Qt Analog Clock after booting? Let us find out how this is achieved.
Start by using the find command in the root project folder to locate any recipes related to the Analog Clock:
$ find layers/ -name "*analogclock*.bb"
We get two outputs, but since Wayland is the window manager, our relevant recipe is wayland-qtdemo-launch-analogclock_1.0.bb. Let's replicate this for our application:
$ mkdir -p layers/meta-article/recipes-graphics/wayland-app-launch
Copy the wayland-qtdemo-launch-analogclock_1.0.bb file into this new directory and rename it to wayland-launch-custom-qt-app_1.0.0.bb. Update its content as follows:
INITIAL_APP_PKGS ?= "qtbase-examples qtwayland"
APPLICATION_ENVIRONMENT ?= 'QT_QPA_PLATFORM=wayland-egl'
WAYLAND_APPLICATION ?= "/opt/DemoProject/bin/DemoProject"
require wayland-app-launch.inc
Note how the WAYLAND_APPLICATION variable is set to the full path of our Qt application, /opt/DemoProject/bin/DemoProject.
Also, copy the wayland-app-launch.inc and wayland-app-launch.service files, maintaining the same folder structure.
After these steps, the meta-article layer should look like this:
layers/meta-article/
...
├── recipes-graphics
│ └── wayland-app-launch
│ ├── wayland-app-launch
│ │ └── wayland-app-launch.service.in
│ ├── wayland-app-launch.inc
│ └── wayland-launch-custom-qt-app_1.0.0.bb
├── recipes-images
│ └── images
│ └── tdx-reference-multimedia-image.bbappend
...
└── recipes-software
└── custom-qt-app
└── custom-qt-app_1.0.0.bb
The final step is to update the image to launch our application instead of the Analog Clock. Navigate to tdx-reference-multimedia-image.bbappend and add:
APP_LAUNCH_WAYLAND:colibri-imx6ull = "wayland-launch-custom-qt-app"
The command above sets a configuration for the Colibri iMX6ULL device. It specifies that the wayland-launch-custom-qt-app should automatically start when the system boots up, specifically within the Wayland window manager environment. This ensures that the custom Qt application for this hardware platform is launched at startup.
After you install this updated image, you can see that the DemoProject application launches at startup.
Could you try interacting with the touch screen? Is everything working correctly? Likely not. Although the app starts, the touch functionality might not work as expected.
To resolve this, you can connect to the board via SSH or USB Debug and initiate the touch calibration process. Follow the on-screen instructions during the calibration:
领英推荐
# weston-touch-calibrator /sys/devices/platform/soc/2100000.bus/21a4000.i2c/i2c-1/1-002c/input/input0/event0
However, expecting the user to initiate touch calibration manually is not ideal. So, let's create another recipe to automate this process at the first boot.
Launching the touch calibration at the first boot
Continuing to improve the user experience in our Yocto Project series, we now focus on launching the touch calibration at the first boot. We aim to automate the touch calibration process using the weston-touch-calibrator tool, ensuring the touch functionality is set up accurately.
The journey begins with crafting a run-touch-calibration-once.sh bash script in the layers/meta-article/recipes-graphics/touch-calibration/files/ directory:
$ mkdir -p layers/meta-article/recipes-graphics/touch-calibration/files/
$ touch layers/meta-article/recipes-graphics/touch-calibration/files/run-touch-calibration-once.sh
The script, tailored for automation, executes the calibration process, checking for successful completion and retrying if necessary. It's set up to attempt calibration multiple times, indicated by the MAX_ATTEMPTS variable, with a function dedicated to running the weston-touch-calibrator:
#!/bin/sh
# run-touch-calibration-once.sh
TOUCH_DEVICE="/sys/devices/platform/soc/2100000.bus/21a4000.i2c/i2c-1/1-002c/input/input0/event0"
MAX_ATTEMPTS=5 # The number of attempts you want
# Function to run weston-touch-calibrator
run_calibration() {
weston-touch-calibrator $TOUCH_DEVICE
return $?
}
attempt=0
success=0
while [ $attempt -lt $MAX_ATTEMPTS ]; do
echo "Attempting touch calibration: Attempt $((attempt + 1))/$MAX_ATTEMPTS"
run_calibration
if [ $? -eq 0 ]; then
echo "Touch calibration successful."
success=1
break
else
echo "Touch calibration failed, retrying..."
fi
attempt=$((attempt + 1))
# Sleep for 2 second before retrying
sleep 2
done
if [ $success -eq 0 ]; then
echo "Touch calibration failed after $MAX_ATTEMPTS attempts."
echo "This service will run again on the next boot."
else
echo "Touch calibration succeeded after $((attempt + 1)) attempts."
echo "Disable this service so it doesn't run on subsequent boots"
systemctl disable run-touch-calibration-once.service
fi
Following the script, we create a systemd service file named run-touch-calibration-once.service to ensure this script runs at startup:
$ touch layers/meta-article/recipes-graphics/touch-calibration/files/run-touch-calibration-once.service
The service file is configured to trigger the calibration script right after the Weston display server starts, running as a one-shot process under root privileges:
[Unit]
Description=Run Weston Touch Calibration on First Boot
After=weston.service
[Service]
Type=oneshot
User=root
Environment=XDG_RUNTIME_DIR=/run/user/0
Environment=WAYLAND_DISPLAY=/run/wayland-0
ExecStart=/usr/bin/run-touch-calibration-once
[Install]
WantedBy=graphical.target
This systemd service file is configured to run a touch calibration script (/usr/bin/run-touch-calibration-once) on the first boot of a system, specifically after the Weston display server weston.service has started. Key environment variables are set for the root user and Weston's display server to ensure proper execution.
The service is activated when the system reaches the graphical target, typically when a graphical environment is fully operational.
Create the run-touch-calibration-once_1.0.0.bb recipe, which integrates this service into our image, ensuring the calibration script is correctly placed and executed in the system:
$ touch layers/meta-article/recipes-graphics/touch-calibration/run-touch-calibration-once_1.0.0.bb
The recipe outlines the installation process for both the script and the service file:
SUMMARY = "Install custom touch calibration service"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
inherit systemd
SRC_URI = "file://run-touch-calibration-once.sh \
file://run-touch-calibration-once.service"
S = "${WORKDIR}"
do_install() {
install -d ${D}${bindir}
install -m 0755 ${S}/run-touch-calibration-once.sh ${D}${bindir}/run-touch-calibration-once
install -d ${D}/${systemd_unitdir}/system
install -m 0644 ${S}/run-touch-calibration-once.service ${D}/${systemd_unitdir}/system/
}
FILES_${PN} += "${D}${bindir}/run-touch-calibration-once"
SYSTEMD_SERVICE:${PN} = "run-touch-calibration-once.service"
The SRC_URI line specifies the source files for this recipe: the shell script run-touch-calibration-once.sh and a systemd service file run-touch-calibration-once.service. These files are expected to be in the same directory as the recipe in the file folder.
In the do_install function, the recipe creates necessary directories in the target image (${D}) for the script and the service file. It then installs the script into /usr/bin/ and the service file into the system's systemd directory, with appropriate permissions set for each (executable for the script and read-only for the service file).
The FILES_${PN} line indicates that the installed script should be included in the package.
Finally, SYSTEMD_SERVICE:${PN} specifies the systemd service that should be enabled and started when the system boots. In this case, it's run-touch-calibration-once.service, which should correspond to the installed service file. This service will handle the execution of the touch calibration script according to the system's startup procedures.
Completing the setup, we must add this new recipe to the tdx-reference-multimedia-image.bbappend file by including the run-touch-calibration-once in the IMAGE_INSTALL variable.
Built and installed the image. We'll see the touch calibration screen after the startup. When the calibration process is finished, the Qt application will start; now, we can control the relay properly.
Perfect! Or almost.
Take a careful look at the screen. Have you noticed the toolbar?
Removing the Weston toolbar
If you've been following my QT5 on iMX6ULL article series, you'd already know that removing the Weston toolbar is crucial for giving a more professional appearance to our solution.
In Qt on iMX6ULL Part 2: Logging messages and settings for debugging, we manually altered the weston.ini file. However, we prefer not to require our users to perform this task after installing the Linux image.
Guess what? No, we won't create a new recipe this time. We'll use a bbappend file to modify the weston.ini file.
Start by finding the recipes related to the weston.ini file configuration:
$ find layers/ -name "*weston*.bb*" | grep weston.ini
You will see several outputs, as depicted:
The layers/openembedded-core/meta/recipes-graphics/wayland/weston-init.bb and layers/meta-toradex-bsp-common/recipes-graphics/wayland/weston-init.bbappend are particularly relevant. The former sets the initial configuration for weston.ini, while the latter adds modifications for the final file configuration. Let's draw inspiration from these for our bbappend.
Create the wayland folder inside recipes-graphics and add the weston-init.bbappend file. Then, include this content:
do_install:append() {
sed -i -e "s/^#\\[shell\\]/[shell]/g" ${D}${sysconfdir}/xdg/weston/weston.ini
sed -i -e "/panel-position=/d" ${D}${sysconfdir}/xdg/weston/weston.ini
sed -i -e "/^\[shell\]/a panel-position=none" ${D}${sysconfdir}/xdg/weston/weston.ini
}
The do_install:append() function modifies the Weston window manager's configuration. It first activates the [shell] section in the weston.ini file. The subsequent commands adjust the panel-position setting, ensuring it is set to none under the [shell] section. These alterations are applied to the weston.ini file in the system's configuration directory.
After whole steps, the project folder structure should now look like this:
layers/meta-article/
├── conf
│ ├── layer.conf
│ └── machine
│ ├── colibri-imx6ull-extra.conf
│ └── include
│ └── colibri-imx6ull.inc
├── COPYING.MIT
├── README.md
├── recipes-bsp
│ ├── tezi-metadata
│ │ ├── files
│ │ │ ├── marketing_article.tar
│ │ │ └── toradexlinux_article.png
│ │ └── tezi-metadata_%.bbappend
│ └── u-boot
│ └── u-boot-toradex_%.bbappend
├── recipes-example
│ └── example
│ └── example_0.1.bb
├── recipes-graphics
│ ├── touch-calibration
│ │ ├── files
│ │ │ ├── run-touch-calibration-once.service
│ │ │ └── run-touch-calibration-once.sh
│ │ └── run-touch-calibration-once_1.0.0.bb
│ ├── wayland
│ │ └── weston-init.bbappend
│ └── wayland-app-launch
│ ├── wayland-app-launch
│ │ └── wayland-app-launch.service.in
│ ├── wayland-app-launch.inc
│ └── wayland-launch-custom-qt-app_1.0.0.bb
├── recipes-images
│ └── images
│ └── tdx-reference-multimedia-image.bbappend
├── recipes-kernel
│ └── linux
│ ├── linux-toradex
│ │ └── my-custom-devicetree-file.dts
│ └── linux-toradex%.bbappend
└── recipes-software
└── custom-qt-app
└── custom-qt-app_1.0.0.bb
22 directories, 21 files
Once you rebuild and install the image, the Weston toolbar should be successfully removed, offering your application a much cleaner and more professional interface.
Conclusion
It's all perfect now!
Throughout this article, we've skillfully integrated QT5 applications, automated startup processes, streamlined touch calibration, and customized user interfaces.
Stay tuned for more insights.
See you there!
Embedded Software Entwickler | Master in Electrical Engineering
1 年Muhammad Usman Rafique follow this