sdlamp2/docs/rg35xx-plus.md
Michael Smith 0f653d4395 Handle SIGTERM/SIGINT for clean shutdown, add device wrapper script
sdlamp2 now catches SIGTERM and SIGINT via a sig_atomic_t flag checked
in the main loop, ensuring position and volume are saved before exit.
Previously, a kill signal would terminate instantly without saving.

New tools/rg35xx-wrapper.sh replaces sdlamp2 as the dmenu_ln CMD on
the RG35XX Plus. Skeleton includes placeholders for WiFi hotspot and
power button monitoring (TBD after on-device investigation).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 15:49:38 +01:00

6.2 KiB
Raw Blame History

Anbernic RG35XX Plus

Device-specific reference for the target hardware. For build instructions see TOOLCHAIN.md.

Hardware

  • Device: Anbernic RG35XX Plus
  • SoC: Allwinner H700 — quad-core ARM Cortex-A53 @ 1.5 GHz (AArch64 / ARMv8-A)
  • GPU: Mali G31 MP2
  • RAM: 1 GB LPDDR4
  • Display: 640×480 IPS

Software

  • OS: Ubuntu 22.04 LTS (Jammy Jellyfish) — modified stock firmware
  • Kernel: Linux 4.9.170 aarch64 (proprietary, no source released by Anbernic)
  • Architecture: aarch64 / arm64 (confirmed via dpkg --print-architecture)
  • glibc: 2.35
  • Userland: Debian/Ubuntu-based (dpkg, apt-get, systemd)

Libraries on Device

All required shared libraries are pre-installed. Most are at /usr/lib/, some at /usr/lib/aarch64-linux-gnu/ (Debian multiarch path):

Library Soname Notes
SDL2 libSDL2-2.0.so.0.12.0 SDL 2.0.12
SDL2_image libSDL2_image-2.0.so.0.900.0 SDL2_image 2.0.9, at multiarch path
libavcodec libavcodec.so.58 FFmpeg ~4.x
libavformat libavformat.so.58 FFmpeg ~4.x
libavutil libavutil.so.56 FFmpeg ~4.x
libswresample libswresample.so.3 FFmpeg ~4.x

Shared libraries are already present — no need to bundle or build them. A native aarch64 compile (e.g. inside the arm64 Docker container) produces working binaries. Must link against glibc ≤ 2.35.

Partition Layout

Device Mount point Filesystem Contents
/dev/mmcblk0p5 / ext4 Root filesystem
/dev/mmcblk0p6 /mnt/vendor ext4 Firmware, apps, scripts
/dev/mmcblk0p7 /mnt/data ext4 User data
/dev/mmcblk0p8 /mnt/mmc vfat ROMs
SD card slot /mnt/sdcard (varies) External storage

Boot Chain

The device uses systemd but boots its UI through a SysV init script that systemd auto-wraps via systemd-sysv-generator. The chain is intentionally layered: launcher.sh runs before partitions are mounted (hardware setup), loadapp.sh runs after mounts (filesystem/network setup + app restart loop), and dmenu_ln is the app dispatcher.

systemd (graphical.target)
  └─ launcher.service  (SysV → auto-generated by systemd-sysv-generator)
       └─ /etc/init.d/launcher.sh start
            ├── mounts /mnt/vendor
            ├── starts brightCtrl.bin (backlight daemon) &
            ├── starts cexpert &
            └── starts loadapp.sh &
                 ├── resizes root partition (first boot only)
                 ├── mounts /mnt/data, /mnt/mmc
                 ├── charging mode: if boot_mode==1 → charger UI → poweroff
                 ├── normal mode: starts NetworkManager, bluetooth, wifi
                 ├── syncs RTC, loads kernel modules, mounts SD card
                 ├── runs /mnt/mod/ctrl/autostart (if exists)
                 └── RESTART LOOP: runs /mnt/vendor/ctrl/dmenu_ln repeatedly
                      └─ /mnt/vendor/ctrl/dmenu_ln
                           ├── selects binary (default: dmenu.bin)
                           ├── config overrides: muos.ini → muos.bin, vpRun.ini → ...
                           ├── runs binary via app_scheduling()
                           └── on exit: executes /tmp/.next (app dispatch for menu)

Why the indirection?

  • launcher.sh — Pre-mount hardware setup: mounts /mnt/vendor, starts backlight and system daemons. Runs as a SysV init script so it integrates with systemd's boot ordering.
  • loadapp.sh — Post-mount filesystem/network setup: mounts data partitions, handles charging mode, starts networking, then enters the restart loop. Runs in the background (&) so launcher.sh can return.
  • dmenu_ln — App dispatcher: selects which binary to run based on config files, wraps execution in app_scheduling() (which sleeps 30s on crash before retrying), and supports /tmp/.next for menu-driven app switching.

app_scheduling behavior

The app_scheduling function in dmenu_ln runs the selected binary. If it exits with a non-zero status, it sleeps 30 seconds before returning, which prevents crash loops from consuming all CPU. The outer while true loop in loadapp.sh then re-invokes dmenu_ln, restarting the application.

Deploying sdlamp2

Overview

The dmenu_ln script already supports switching the startup binary via config files (e.g. muos.inimuos.bin). We follow the same pattern to launch sdlamp2 instead of the default menu.

Setup

  1. Copy the binary and wrapper to the device:

    scp build/sdlamp2 root@<device>:/mnt/vendor/bin/sdlamp2
    scp tools/rg35xx-wrapper.sh root@<device>:/mnt/vendor/bin/rg35xx-wrapper.sh
    
  2. Add the config check to /mnt/vendor/ctrl/dmenu_ln. In the section where CMD overrides are checked (after the existing muos.ini / vpRun.ini checks, before the app_scheduling call), add:

    if [ -f "/mnt/vendor/sdlamp2.ini" ];then
        CMD="/mnt/vendor/bin/rg35xx-wrapper.sh"
    fi
    

    The wrapper script handles device-specific concerns (WiFi hotspot, power button monitoring) and launches sdlamp2 as its main foreground process. See tools/rg35xx-wrapper.sh for details.

  3. Enable sdlamp2 on boot:

    touch /mnt/vendor/sdlamp2.ini
    
  4. Disable (revert to normal menu):

    rm /mnt/vendor/sdlamp2.ini
    

What's preserved

Everything else in the boot chain continues to work:

  • Charging mode — handled in loadapp.sh before the restart loop
  • LED/backlight controlbrightCtrl.bin started by launcher.sh
  • Clean shutdown — sdlamp2 handles SIGTERM/SIGINT, saving position and volume before exit. The wrapper script can trigger poweroff after sdlamp2 exits
  • Restart on exit — if sdlamp2 exits cleanly (status 0), the restart loop in loadapp.sh re-launches it immediately
  • Crash recovery — if sdlamp2 crashes (non-zero exit), app_scheduling sleeps 30s then the loop retries
  • Easy revert — removing sdlamp2.ini restores the stock menu on next boot