UNA-Watch Simulatorο
The UNA Simulator runs on Windows (via TouchGFX Designer and Visual Studio) and on x86-64 Linux (via GCC and SDL2). The Getting Started steps below cover the Windows workflow for the TouchGFX apps; for Linux, see Linux (GCC). The LVGL simulators are plain CMake projects that need a compiler and SDL2 but no IDE.
Note: If you move the application to another location, you need to update the relative path to TouchGFX library path.
See: Transfer Application
Getting Startedο
Need Componentsο
Download and install TouchGFX Designer.
If you want to work with UNA Simulator in Visual Studio, then:
Download and install Visual Studio.
In the Installing window, where you select the required packages, go to Workloads β Desktop & Mobile and choose Desktop development with C++.
In Installation Details, for Desktop development with C++ select MSVC v143, then click Install.
Install UNA_SDK variable {#install-una-sdk-variable}ο
Run the PowerShell script export-stm32-tools.ps1, located in:
Utilities\Scripts\export-stm32-tools.ps1This script sets the UNA_SDK environment variable and configures STM32 tools.
Start Simulatorο
TouchGFX Designerο
TouchGFX Designer does not support Debug mode. If you want to debug the project, use Visual Studio.
Open
<name>.touchgfx, located in:
<app_name>\Software\Apps\TouchGFX-GUIWhen opening the project for the first time, click Generate Code (F4). This only needs to be done once.
Click Run Simulator (F5).
Visual Studioο
This step only needs to be done once. Open the application project in TouchGFX Designer and click Generate Code (F4).
Go to:
<app_name>\Software\Apps\TouchGFX-GUI\simulator\msvsOpen the Application.vcxproj file.
Start debugging by pressing F5.
Simulationο
Buzzerο
Buzzer actions are printed in the terminal as log messages. Example:
I- Mock.Buzzer::play::39 : [0] time=150 ms, level=3 I- Mock.Buzzer::play::39 : [1] time=100 ms, level=0 I- Mock.Buzzer::play::39 : [2] time=150 ms, level=3
Explanation:
[] β note array index
time β duration in milliseconds
level β sound level (1β3), 0 means no sound
Backlightο
Backlight actions are printed in the terminal as log messages.
I- Mock.Backlight::on::22 : called, timeout = 5000 I- Mock.Backlight::off::30 : off backlight
There are two types of log messages:
turning the backlight on with a timeout in milliseconds
turning the backlight off
Vibroο
Vibro actions are printed in the terminal as log messages.
I- Mock.Vibro::play::31 : play(melody[1]) I- Mock.Vibro::play::34 : [0] effect=1, loop=0, pause=0
Explanation:
[] β note array index
effect β vibration effect ID
loop β number of repetitions
pause β pause between effects
Sensorsο
In the file ConfigurationSimulator.hpp, you can enable/disable sensor simulation and configure parameters.
Location:
<app-name>\Software\Apps\TouchGFX-GUI\simulator
For examples of sensor integration and data handling, see the Sensors Tutorial.
GPSο
Simulates speed, altitude, and distance.
The simulated user moves around a stadium track.
Includes a timer for satellite acquisition.
Can simulate GPS signal loss.
Adds noise to latitude/longitude.
Configuration options:
enable/disable sensor
minimum and maximum speed
satellite search time
//GPS Sensor
#define GPS_SIM_ENABLE 1 // 0 - Disable
#define GPS_SIM_SPEED_MIN 20 // km/h
#define GPS_SIM_SPEED_BASE 25 // km/h
#define GPS_SIM_SPEED_MAX 30 // km/h
#define GPS_SIM_TIME_SEARCH_SATELLITE 7 // seconds
Heart Rateο
Simulates:
HR (Heart Rate)
AHR (Average Heart Rate)
RHR (Resting Heart Rate)
trust level
Options:
enable/disable sensor
minimum and maximum heart rate
training type (Cycling / Hiking / Running)
//HeartRate Sensor
#define HEART_RATE_SIM_ENABLE 1 // 0 - Disable
#define HEART_RATE_SIM_MIN_HR 50
#define HEART_RATE_SIM_MAX_HR 140
#define HEART_RATE_SIM_TYPE_TRAINING 0 // 0 - Cycling, 1 - Hiking, 2 - Running
Battery Levelο
Simulates battery voltage drop.
Options:
enable/disable sensor
initial value
decrease step
// Battery Level Sensor
#define BATT_LEVEL_SIM_ENABLE 1 // 0 - Disable
#define BATT_LEVEL_SIM_START_VALUE 100 // 10 - 100%
#define BATT_LEVEL_SIM_STEP_VALUE 0.1 //percent
Pressureο
Simulates Presure value.
Options:
enable/disable sensor
set value pressure, which changes in a small range
// Pressure Sensor
#define PRESSURE_SIM_ENABLE 1 // 0 - Disable
#define PRESSURE_SIM_PRESS_VALLUE 1020.2
IMU Wrist Detectionο
Simulates wrist detection.
A wrist detection event activates the backlight for 5 seconds.
Options:
enable/disable sensor
change the key used to trigger the event
To simulate a wrist detection event, press key 5.
// IMU Writs Sensor
#define IMU_WRIST_SIM_ENABLE 1 // 0 - Disable
#define IMU_WRIST_SIM_WRIST_DETECT_KEY 5
IMU Step Counterο
Simulates Step Counter. Step Counter get Speed with the GPS Speed module and convert to steps.
Options:
enable/disable sensor
// IMU StepCounter Sensor
#define IMU_STEP_COUNTER_SIM_ENABLE 1 // 0 - Disable
Include Header & Source fileο
MSVSο
Open Application.vcxproj in a text editor: `<app_name>\Software\Apps\TouchGFX-GUI\simulator\msvs
Add header paths to ClInclude.
Add source file paths to ClCompile.
GCC {#gcc}ο
Open MakeFile in text editor:
<app-name>\Software\Apps\TouchGFX-GUI\simulator\gccAdd header paths to ADDITIONAL_INCLUDE_PATHS.
Add source file paths to ADDITIONAL_SOURCES_UNA.
The two lists describe the same build, so a file added to one must be added to
the other. A mismatch is not caught by a normal build: CI builds the GCC side
only, so a source missing from the vcxproj first shows up as a link error when
someone opens the project in Visual Studio. The MSVS Source Sync workflow
compares both lists on every pull request that touches either file. To run the
same check locally, from the SDK root (python on Windows):
python3 .github/scripts/check_msvs_sources.py
Transfer Application {#transfer-application}ο
If you move the application to another location, you need to update the TouchGFX library path.
Open
<name>.touchgfxin text editor:<app_name>\Software\Apps\TouchGFX-GUIFind βTouchGfxPathβ: and update the relative path to
<una_sdk>/ThirdParty/touchgfx.Example:"SelectedStartupLanguage": "GB", "TouchGfxPath": "touchgfx", "UIPath": ".",
If you move the una_sdk folder, you must update UNA_SDK environment variable. See: Install UNA_SDK variable
Regenerate the GUI {#regenerate-gui}ο
Code generation normally runs from TouchGFX Designer (Generate Code, F4). The
same job runs headlessly with tgfx, the command line tool that ships with a
TouchGFX installation. Installing TouchGFX does not put it on PATH, so call it
by full path; on Windows that is <touchgfx-install>\designer\tgfx.exe. Run it
from the appβs TouchGFX-GUI directory:
& "<touchgfx-install>\designer\tgfx.exe" generate -p <name>.touchgfx
-p accepts either the .touchgfx file or the directory that holds it. The
command prints nothing on success unless -v is given, and --clean forces a
full regenerate. A run that changes no file content leaves no diff.
Generation rewrites two tracked files, config/gcc/app.mk and
config/msvs/Application.props, with paths taken from the machine that ran it.
Restore them before committing, so that a local installation path does not travel
into the repository:
git checkout -- config/gcc/app.mk config/msvs/Application.props
That discards every unstaged change in those two files, not only the ones generation just made, so commit or stash your own edits to them first.
Set a TouchGFXEnvPath environment variable when TouchGFX is installed somewhere
other than the path Application.props names, otherwise the Visual Studio asset
pre-build cannot find the converters. The variable only wins where the project
declares the property conditionally:
<TouchGFXEnvPath Condition="'$(TouchGFXEnvPath)' == ''">...</TouchGFXEnvPath>
MSBuild gives a project property precedence over an environment one, so a project that pins the path unconditionally ignores the variable and has to be edited instead.
LVGL simulator {#lvgl-simulator}ο
Apps whose GUI is built on LVGL rather than TouchGFX (the tutorialsβ LVGL-GUI
variants, starting with HelloWorld, and the
RunLVGL activity app) simulate through the same mock
kernel, but with a plain CMake project (LVGL-GUI/simulator/CMakeLists.txt) instead of
the Designer-generated Visual Studio solution and gcc Makefile. SDK::Simulator::LvglHost (Libs/Source/Simulator/LVGL)
stands in for the kernelβs display, ticks and buttons: an SDL2 window shows the frames
the LVGL port sends, a thread posts EVENT_GUI_TICK at the watchβs frame rate, and the
keyboard stands in for the buttons. Keys 1-4 are the physical buttons L1, L2, R1, R2:
key down sends the press event, key up sends the release, and a key up within 500 ms
sends a click first, the sequence the kernel emits. The q/w/e/r row sends one
press and the a/s/d/f row one release for the same four buttons, the way the
TouchGFX simulators pass those codes from SDK/GUI/Button.hpp straight through (the
z chord has no key). cmake/una-simulator.cmake
provides the source lists and una_simulator_link_sdl2(), which uses an installed SDL2
where CMake can find one and otherwise, on Windows, the 32-bit SDL2 shipped with
TouchGFX Designer. The buildβs architecture must match the SDL2 it links: 32-bit with the
TouchGFX copy, x64 with a 64-bit installed package. The compiler is whatever CMake
finds: GCC on Linux and WSL, MSVC on Windows. MSVC comes with the free Build Tools for
Visual Studio as well as with the IDE, whose βC++ CMake tools for Windowsβ component
also brings CMake and Ninja; the Ninja generator drives it from a developer command
prompt (the x86 one for the 32-bit build), and the Visual Studio generator (-A Win32)
works from any shell and also writes a solution to open in the IDE. Neither
TouchGFX Designer nor Visual Studio is needed when SDL2 is installed. The sensor
simulation, mock file system and keyboard mapping above apply unchanged.
.github/workflows/linux-simulator.yml builds these CMake simulators on Linux and
smoke-runs them headlessly, beside the TouchGFX ones.
Linux (GCC) {#linux-gcc}ο
The simulator builds and runs on x86-64 Linux using GCC and SDL2. TouchGFX Designer is Windows-only, so on Linux you build and run directly from the command line rather than through the Designer/Visual Studio GUI.
Build and runο
This assumes the SDK is cloned and UNA_SDK is exported, per SDK Setup. Unlike the firmware build, the desktop simulator does not need the ST ARM toolchain; it needs GCC, SDL2, and Ruby.
From an appβs TouchGFX-GUI directory (for example Examples/Apps/Running/Software/Apps/TouchGFX-GUI):
# Simulator dependencies (Debian/Ubuntu)
sudo apt-get install -y build-essential libsdl2-dev libsdl2-image-dev libjpeg-dev ruby ruby-nokogiri
# Build (UNA_SDK is the absolute path to the repo root)
UNA_SDK=/absolute/path/to/una-sdk make -f simulator/gcc/Makefile -j"$(nproc)"
# Run headless (no X display needed)
SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy ./build/bin/simulator.out
The build links touchgfx SDL2 SDL2_image jpeg rt m pthread dl. To add your own headers or sources to the Linux build, edit simulator/gcc/Makefile (ADDITIONAL_INCLUDE_PATHS / ADDITIONAL_SOURCES_UNA), as described under GCC above.
What makes the Linux build workο
Linux support is spread across the repo rather than in one place:
SDK (
Libs/) β the simulator layer is platform-split with#ifdef _WIN32/#else: POSIXGetTickCount64()/Sleep()shims (viaclock_gettimeandusleep), adirent-based FileSystem backend, message-sizestatic_asserts guarded to 32-bit (ARM) builds with#if __SIZEOF_POINTER__ == 4, and a C-valid plainstrncpyinStdLibWrappers.c.Vendored TouchGFX tooling (
ThirdParty/) β the Linux asset converters carry the execute bit and thetextconvertRuby scripts run on modern Ruby. SeeThirdParty-Local-Patches.md.Per-app config β each
TouchGFX-GUIproject tracksconfig/gcc/app.mk(it holds the repo-relativetouchgfx_paththe Linuxuna/Makefilehard-includes), adds-no-pieto the Linux linker options inuna/Makefile, and guards itsWindows.hinclude with#ifdef _WIN32.CI β
.github/workflows/linux-simulator.ymlbuilds and headlessly smoke-runs the simulator (non-gating).