Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
9b0d95a
Add PR build/test CI and fix broken ENABLE_TESTS wiring
MrDavid5465 Aug 25, 2026
0e336fc
feat(flatpak): add Flatpak packaging
MrDavid5465 Aug 30, 2026
ec7bcab
fix(flatpak): add CMAKE_POLICY_VERSION_MINIMUM for old CMakeLists.txt
MrDavid5465 Aug 30, 2026
6a291a9
fix(flatpak): allow implicit-function-declaration for argtable2
MrDavid5465 Aug 30, 2026
d269289
fix(flatpak): add CMAKE_POLICY_VERSION_MINIMUM for hidapi
MrDavid5465 Aug 30, 2026
d032920
fix(flatpak): add simapi submodule source, disable GUI for now
MrDavid5465 Aug 30, 2026
042df11
fix: add libuv module, fix libproc2 UNKNOWN-version detection
MrDavid5465 Aug 30, 2026
0dea75d
feat(flatpak): enable BUILD_GUI, add nappgui submodule source
MrDavid5465 Aug 30, 2026
bebdb55
fix(flatpak): manually install argtable2's header/library
MrDavid5465 Aug 30, 2026
da5cdec
fix(flatpak): build only the real targets, skip broken scratch test
MrDavid5465 Aug 30, 2026
605a460
fix: comment out broken simlighttest scratch executable
MrDavid5465 Aug 30, 2026
d4af451
fix(flatpak): add /app/lib to the linker search path
MrDavid5465 Aug 30, 2026
ce76e8a
fix(flatpak): use LIBRARY_PATH env var instead of EXE_LINKER_FLAGS
MrDavid5465 Aug 30, 2026
9ad847c
fix(flatpak): build argtable2 as a shared library
MrDavid5465 Aug 30, 2026
a5e4aa5
fix(flatpak): fix exit-code propagation in argtable2 install loop
MrDavid5465 Aug 30, 2026
79376a2
fix(flatpak): drop non-square icon for now
MrDavid5465 Aug 30, 2026
6e5c8bc
docs(flatpak): document the fully verified local build
MrDavid5465 Aug 30, 2026
d5ee172
fix(ci): remove submodules: recursive from checkout step
MrDavid5465 Aug 30, 2026
06ae17d
fix(flatpak): remove dangling Icon= reference from desktop file
MrDavid5465 Aug 30, 2026
1a1cc99
fix(flatpak): add a properly square icon
MrDavid5465 Aug 30, 2026
a0fc457
ci: build deb/rpm packages in containers instead of self-hosted runners
MrDavid5465 Aug 30, 2026
099c723
ci: fix container workspace path and retry flaky Fedora dep install
MrDavid5465 Aug 30, 2026
0849c61
Merge remote-tracking branch 'origin/feature/flatpak-verify' into fea…
MrDavid5465 Aug 30, 2026
a3f19a7
refactor: move square icon to tools/monocoque.svg for sharing with Ap…
MrDavid5465 Aug 30, 2026
65c379c
ci: add AppImage build and fold Flatpak into the same release
MrDavid5465 Aug 30, 2026
8c1cd60
ci: build the AppImage on ubuntu-24.04, not 22.04
MrDavid5465 Aug 30, 2026
0426fe7
Merge remote-tracking branch 'origin/feature/ci-test-automation' into…
MrDavid5465 Aug 30, 2026
c709832
gitignore: exclude local flatpak-builder outputs
MrDavid5465 Aug 30, 2026
aad0dd2
ci: generate release notes automatically
MrDavid5465 Aug 30, 2026
389e17d
ci: stamp the package version from the tag
MrDavid5465 Aug 30, 2026
97b1692
fix(flatpak): grant real X11 so the GUI can open a display
MrDavid5465 Aug 30, 2026
f98346d
fix(flatpak): grant monocoque its own config and cache directories
MrDavid5465 Aug 30, 2026
1990a37
fix(flatpak): share the host /dev/shm so simd's telemetry is visible
MrDavid5465 Aug 30, 2026
0265bda
fix(packaging): name deb dependencies that still exist on the target …
MrDavid5465 Aug 30, 2026
ed4124d
fix: zero the settings structs so --help does not free garbage
MrDavid5465 Aug 30, 2026
51695f9
fix(gui): stop gmonocoque segfaulting on a config without an api key
MrDavid5465 Aug 30, 2026
95b8c2e
feat: build simd alongside monocoque
MrDavid5465 Aug 31, 2026
7c26b1f
ci: ship simd in the deb, rpm and AppImage packages
MrDavid5465 Aug 31, 2026
7960618
ci: check out submodules for the rpm legs
MrDavid5465 Aug 31, 2026
ee3773b
feat(flatpak): bundle simapi and simd, and let them see the host
MrDavid5465 Aug 31, 2026
23afb6a
fix(sound): return from sounddev_init so shaker devices survive setup
MrDavid5465 Aug 31, 2026
ea27ec6
fix(flatpak): read the host process table in a way that survives real…
MrDavid5465 Aug 31, 2026
0edd605
packaging: carry licence and copyright notices in the bundles
MrDavid5465 Sep 1, 2026
bf6e72e
ci: only publish releases from tags
MrDavid5465 Sep 1, 2026
bc37044
ci: adopt release-please for versioning and release notes
MrDavid5465 Sep 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
480 changes: 462 additions & 18 deletions .github/workflows/ci.yaml

Large diffs are not rendered by default.

31 changes: 31 additions & 0 deletions .github/workflows/pr-build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: PR Build & Test

on:
pull_request:
push:
branches: [ "master" ]

jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Checkout submodules
run: git submodule update --init --recursive
- name: Update apt
run: sudo apt update
- name: Install dependencies
# Same list as ci.yaml's ubuntu-latest leg, minus the GUI-only deps
# (libgtk-3-dev, libglu1-mesa-dev) and libcurl4-openssl-dev — this
# workflow builds the CLI + test suite only, not the GUI.
#
# libyder-dev is for the simd target, which builds by default. Kept
# here rather than turning BUILD_SIMD off so a PR that breaks simd
# fails its checks instead of only the release build.
run: sudo apt install -y libuv1-dev libargtable2-dev libserialport-dev libconfig-dev libhidapi-dev liblua5.4-dev libxdg-basedir-dev libxml2-dev libpulse-dev libproc2-dev libyder-dev
- name: Configure CMake
run: cmake -B build -DENABLE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug
- name: Build
run: cmake --build build --config Debug
- name: Run tests
run: ctest --test-dir build --output-on-failure
38 changes: 38 additions & 0 deletions .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: release-please

on:
push:
branches: [ master ]

permissions:
contents: write
pull-requests: write

jobs:
release-please:
runs-on: ubuntu-latest
outputs:
release_created: ${{ steps.release.outputs.release_created }}
tag_name: ${{ steps.release.outputs.tag_name }}
steps:
- uses: googleapis/release-please-action@v4
id: release
with:
config-file: release-please-config.json
manifest-file: .release-please-manifest.json

# Builds and uploads the packages for the release that was just cut.
#
# This calls ci.yaml rather than relying on its `push: tags` trigger,
# because a tag pushed with the default GITHUB_TOKEN does not start a new
# workflow -- GitHub blocks that deliberately, to stop workflows triggering
# each other in a loop. Calling it keeps the whole release inside one run
# and avoids storing a personal access token on a public repository.
build-release:
needs: release-please
if: needs.release-please.outputs.release_created == 'true'
uses: ./.github/workflows/ci.yaml
with:
release_tag: ${{ needs.release-please.outputs.tag_name }}
permissions:
contents: write
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,9 @@
/src/monocoque/simulatorapi/simapi

.vscode

# flatpak-builder outputs from local builds -- CI regenerates these.
# flatpak/repo in particular is an OSTree store: ~1000 binary objects.
/flatpak/repo/
/flatpak/build-dir/
/flatpak/.flatpak-builder/
1 change: 1 addition & 0 deletions .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ ".": "0.3.6" }
137 changes: 82 additions & 55 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ SET_SOURCE_FILES_PROPERTIES( src/monocoque.c PROPERTIES LANGUAGE C)

option(BUILD_GUI "Build GUI support" OFF)
option(BUILD_SHARED "Build monocoque shared library" OFF)
option(ENABLE_TESTS "Build test suite" OFF)


project(monocoque)
Expand Down Expand Up @@ -72,9 +73,15 @@ pkg_check_modules(LIBPROC2 libproc2)
if (LIBPROCPS_FOUND)
#add_compile_definitions(USE_OLD_PID_VAL=0)
elseif (LIBPROC2_FOUND)
if (LIBPROC2_VERSION VERSION_GREATER_EQUAL "4.0.5")
#add_compile_definitions(USE_OLD_PID_VAL=0)
else()
# Some distro packagings (e.g. the freedesktop Flatpak SDK) ship a
# libproc2.pc with `Version: UNKNOWN` rather than a real version
# string. VERSION_GREATER_EQUAL against that always evaluates false,
# silently falling through to the old (pre-4.0.5) PIDS_VAL API and
# failing to compile against an actually-current libproc2 whose real
# header has already moved to the new 3-argument macro. Only take the
# old-API branch when the version string is genuinely parseable and
# actually old.
if (LIBPROC2_VERSION MATCHES "^[0-9]" AND LIBPROC2_VERSION VERSION_LESS "4.0.5")
add_compile_definitions(USE_OLD_PID_VAL=1)
endif()
else()
Expand Down Expand Up @@ -107,57 +114,6 @@ endif()



#add_executable(listusb tests/testlibusb.c)
#target_include_directories(listusb PUBLIC)
#target_link_libraries(listusb portaudio hidapi-hidraw)
#add_test(listusb list-usb-devices listusb)

#add_executable(testrevburner tests/testrevburner.c)
#target_include_directories(testrevburner PUBLIC)
#target_link_libraries(testrevburner hidapi-hidraw)
#add_test(testrevburner testrevburner)

#add_executable(listsound tests/pa_devs.c)
#target_include_directories(listsound PUBLIC)
#target_link_libraries(listsound m portaudio)
#add_test(list-sound-devices listsound)
#
#add_executable(longsine tests/patest_longsine.c)
#target_include_directories(longsine PUBLIC ${LIBXML_INCLUDE_DIR})
#target_link_libraries(longsine m portaudio)
#add_test(longsine longsine)
#
#add_executable(parserevburnerxml tests/revburnerparsetest.c)
#target_include_directories(parserevburnerxml PUBLIC ${LIBXML_INCLUDE_DIR})
#target_link_libraries(parserevburnerxml portaudio xml2)
#add_test(parserevburnerxml parserevburnerxml)
#
add_executable(setmem tests/setmem.c)
target_include_directories(setmem PUBLIC)
target_link_libraries(setmem)
add_test(setmem setmem)

add_executable(getmem tests/getmem.c)
target_include_directories(getmem PUBLIC)
target_link_libraries(getmem)
add_test(getmem getmem)
#
#add_executable(setsimdata tests/setsimdata.c)
#target_include_directories(setsimdata PUBLIC)
#target_link_libraries(setsimdata)
#add_test(setsimdata setsimdata)
#
#add_executable(hidtest tests/hidtest.c)
#target_include_directories(hidtest PUBLIC)
#target_link_libraries(hidtest hidapi-hidraw)
#add_test(hidtest hidtest)
#
add_executable(simlighttest tests/simlighttest.c)
target_include_directories(simlighttest PUBLIC)
target_link_libraries(simlighttest serialport)
add_test(simlighttest simlighttest)


# used for enabling additional compiler options if supported
include(CheckCXXCompilerFlag)

Expand Down Expand Up @@ -221,6 +177,77 @@ endif()
# unit tests --only enable if requested AND we're not building as a sub-project
if(ENABLE_TESTS AND NOT MONOCOQUE_SUBPROJECT)
message(STATUS "[monocoque] Unit Tests Enabled")
add_subdirectory(tests)
enable_testing()
add_subdirectory(tests)
endif()

# simd -- the telemetry daemon everything else here reads from. simapi ships
# its own CMakeLists with a BUILD_SIMD option, but this tree never invokes it:
# src/monocoque/simulatorapi compiles simapi's sources straight into the static
# `simulatorapi` library instead. So the target is declared here over that same
# library, which also means the simd in a monocoque package is built from the
# exact simapi commit monocoque itself was built against, rather than whatever
# happens to be installed system-wide.
#
# Packaged alongside monocoque because monocoque does nothing without it: with
# no simd running, simapi_get_sim() finds no /dev/shm/SIMAPI.DAT and falls back
# to scanning /proc for the game itself.
option(BUILD_SIMD "Build the simd telemetry daemon alongside monocoque" ON)
if(BUILD_SIMD)
set(SIMAPI_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/monocoque/simulatorapi/simapi)
add_executable(simd
${SIMAPI_SRC_DIR}/simd/simd.c
${SIMAPI_SRC_DIR}/simd/parameters.c
${SIMAPI_SRC_DIR}/simd/confighelper.c
${SIMAPI_SRC_DIR}/simd/dirhelper.c
${SIMAPI_SRC_DIR}/simd/poke.c
# Not part of the simulatorapi library above, which only pulls in
# mapacdata.c from simmap/.
${SIMAPI_SRC_DIR}/simmap/mapsimdata.c)
# simd's own build prefers argtable3 and falls back to argtable2. monocoque
# links argtable2 everywhere, so pin the same one rather than let two halves
# of one package disagree about which argtable they need at runtime.
# simd.c carries its own copy of is_pid_running(), and so does simapi's
# getpid.c. Upstream links simd against libsimapi.so, where the executable's
# definition simply wins; here simapi is a static archive and the linker
# refuses the duplicate outright. Renaming simd's copy for its own
# translation units keeps both definitions and leaves each caller bound to
# the one it was written against -- no patch to the pinned submodule, and no
# --allow-multiple-definition silently picking a winner.
target_compile_definitions(simd PRIVATE HAVE_ARGTABLE2 is_pid_running=simd_is_pid_running)
target_include_directories(simd PRIVATE
${SIMAPI_SRC_DIR}/simapi
${SIMAPI_SRC_DIR}/include
${SIMAPI_SRC_DIR}/simmap
${SIMAPI_SRC_DIR}/simd)
target_link_libraries(simd m dl uv yder argtable2 config simulatorapi proc2)
# orcania sits under yder. A shared libyder.so records that dependency and
# pulls it in on its own, which is why Debian and Ubuntu need nothing here;
# a static libyder.a records nothing, so every o_malloc/split_string it
# calls comes back undefined. Fedora has no yder package at all and its rpm
# job vendors both as static archives, so the link has to name orcania
# explicitly -- after yder, which is the order a static link needs.
find_library(ORCANIA_LIBRARY orcania)
if(ORCANIA_LIBRARY)
target_link_libraries(simd ${ORCANIA_LIBRARY})
endif()
endif()

install(TARGETS monocoque-cli RUNTIME DESTINATION bin)
if(BUILD_GUI)
install(TARGETS monocoque-gui RUNTIME DESTINATION bin)
endif()
if(BUILD_SIMD)
install(TARGETS simd RUNTIME DESTINATION bin)
# simd runs without ~/.config/simd/simd.config, but degraded: it logs
# "Error with config file" then "Disabling Automatic Bridge Mode" and
# carries on mapping telemetry (observed by running it with an empty home
# bind-mounted over the real one). What it loses is the auto-bridge -- the
# per-game launchexe/liveexe table that starts the Windows bridge under
# Proton, which is how a sim's telemetry reaches /dev/shm at all. simapi's
# own build installs this file straight into $HOME, which a package must
# not do, so it ships as an example to copy. Note simd resolves that path
# from getpwuid(), not $HOME.
install(FILES ${SIMAPI_SRC_DIR}/simd/conf/simd.config DESTINATION share/monocoque)
endif()
install(FILES tools/monocoque.desktop DESTINATION share/applications)
9 changes: 9 additions & 0 deletions flatpak/io.github.spacefreak18.monocoque.desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[Desktop Entry]
Version=1.0
Type=Application
Name=Monocoque
Comment=Device manager for racing sims
Exec=gmonocoque
Icon=io.github.spacefreak18.monocoque
Terminal=false
Categories=Game;Development;
27 changes: 27 additions & 0 deletions flatpak/io.github.spacefreak18.monocoque.metainfo.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>io.github.spacefreak18.monocoque</id>
<name>Monocoque</name>
<summary>Device manager for racing sims</summary>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0-only</project_license>
<description>
<p>
Monocoque bridges telemetry from supported racing simulators to
peripheral devices such as haptic shakers, LED strips, shift lights,
and sim wind fans, and exposes a local API for third-party dashboard
and configuration tools.
</p>
</description>
<launchable type="desktop-id">io.github.spacefreak18.monocoque.desktop</launchable>
<provides>
<binary>monocoque</binary>
<binary>gmonocoque</binary>
</provides>
<url type="homepage">https://spacefreak18.github.io/simapi/monocoque.html</url>
<url type="vcs-browser">https://github.com/Spacefreak18/monocoque</url>
<content_rating type="oars-1.1" />
<releases>
<release version="0.3.6" date="2026-08-21" />
</releases>
</component>
Loading