Skip to content

Latest commit

 

History

History
374 lines (252 loc) · 8.65 KB

File metadata and controls

374 lines (252 loc) · 8.65 KB

LessUI Development Guide

This guide covers building LessUI, running tests, and contributing code.

Building LessUI

LessUI uses Docker to cross-compile for ARM devices. You don't need the actual hardware to build.

Prerequisites

  • Docker Desktop
  • Make (pre-installed on macOS/Linux)
  • Git

Quick Start

Build everything:

make

Build for one platform:

make PLATFORM=miyoomini

Available platforms: miyoomini, my282, my355, trimuismart, rg35xx, rg35xxplus, rgb30, tg5040, m17, magicmini, zero28

Deprecated platforms: gkdpixel (no longer supported)

macOS Native Development (Fastest Workflow)

For rapid UI development on macOS, build and run natively without Docker:

# First-time setup: Install SDL2 libraries
brew install sdl2 sdl2_image sdl2_ttf

# Build and run launcher
make dev-run

This gives you:

  • Instant builds (native compiler, no Docker overhead)
  • Live debugging with AddressSanitizer
  • Visual testing in SDL2 window (640×480 or 854×480)
  • Keyboard controls: Arrow keys (D-pad), A/S/W/Q (buttons), Enter (Start), Space (Menu)
  • Quit: Hold Backspace/Delete

The fake SD card lives at workspace/desktop/FAKESD/. Add test ROMs there:

mkdir -p workspace/desktop/FAKESD/Roms/GB
cp ~/Downloads/game.gb workspace/desktop/FAKESD/Roms/GB/

Development commands:

make dev        # Build launcher for macOS
make dev-run    # Build and run launcher
make dev-clean  # Clean macOS build artifacts

Limitations:

  • macOS platform is for launcher development only
  • Cannot test libretro cores (player) - use actual hardware
  • Hardware features stubbed (brightness, volume, power)

Platform Shell (for development)

Drop into a build environment for interactive development:

make PLATFORM=miyoomini shell

Inside the container you can build components individually:

cd /root/workspace/all/launcher
make

Code Quality

Run All Checks

make test        # Run unit tests
make lint        # Static analysis
make format      # Auto-format code

Static Analysis

Find bugs before they ship:

make lint        # Check common code

This runs clang-tidy on workspace/all/ which contains all the platform-independent code.

Unit Tests

LessUI uses Unity for testing:

make test

Tests live in tests/unit/ and mirror the structure of workspace/all/. For example, workspace/all/common/utils.c has tests in tests/unit/all/common/test_utils.c.

Writing Tests

Here's an example test:

#include "unity.h"
#include "utils.h"

void test_getDisplayName_stripsExtension(void) {
    char result[256];
    getDisplayName("game.gb", result);
    TEST_ASSERT_EQUAL_STRING("game", result);
}

Add your test function to the main() function in your test file:

int main(void) {
    UNITY_BEGIN();
    RUN_TEST(test_getDisplayName_stripsExtension);
    return UNITY_END();
}

Run tests: make test

Code Formatting

LessUI uses clang-format with tabs and K&R-style braces:

make format            # Format all code
make format-check      # Check without changing

Settings in .clang-format:

  • Tabs for indentation (width: 4)
  • Opening braces on same line
  • Left-aligned pointers (char* name)
  • 100 character line limit

Shell Script Linting

Check shell scripts with shellcheck:

make lint-shell

Project Structure

LessUI/
├── workspace/
│   ├── all/              # Platform-independent code
│   │   ├── launcher/        # Launcher
│   │   ├── player/       # Libretro frontend
│   │   └── common/       # Shared utilities and API
│   │
│   └── <platform>/       # Platform-specific code
│       ├── platform/     # Hardware definitions
│       ├── keymon/       # Button monitoring daemon
│       └── libmsettings/ # Settings library
│
├── skeleton/             # Files copied to SD card
│   ├── SYSTEM/res/       # Shared assets (fonts, sprites)
│   └── BOOT/             # Boot scripts
│
├── build/                # Build output (generated)
├── tests/                # Unit tests
└── docs/                 # Documentation

Platform Architecture

LessUI uses a platform abstraction layer so one codebase supports 20+ devices:

Common code (workspace/all/) calls abstract APIs like:

  • GFX_clear() - Clear screen
  • PAD_poll() - Read buttons
  • PWR_getBatteryLevel() - Get battery %

Platform code (workspace/<platform>/platform/) implements these for specific hardware:

  • platform.h - Hardware constants (screen size, button codes)
  • platform.c - Hardware functions (if needed)

Example from platform.h:

#define FIXED_WIDTH 640
#define FIXED_HEIGHT 480
#define BUTTON_A SDLK_SPACE

The common code compiles once, then links with different platform definitions for each device.

Adding Features

Making Changes to Common Code

  1. Edit files in workspace/all/
  2. Write tests in tests/unit/
  3. Run make test to verify
  4. Format with make format
  5. Check with make lint

Adding Platform-Specific Features

  1. Edit workspace/<platform>/platform/ files
  2. Test on actual hardware (cross-compilation can't verify hardware behavior)
  3. Document in workspace/<platform>/README.md

Testing Your Changes

Build for a specific platform:

make PLATFORM=miyoomini build

Output goes to build/ directory. Copy to SD card and test on device.

Contributing

Before You Submit

  1. Run all checks:
make test lint format
  1. Test on at least one platform if possible

  2. Update documentation:

    • Platform README if hardware-specific
    • CLAUDE.md if changing architecture
    • This file if changing workflows

Commit Messages

Keep it simple:

Add battery percentage to status bar

Show battery % next to icon when available.
Fallback to icon-only on platforms without %.

First line is summary (imperative mood). Body explains why and what changed.

Common Tasks

Adding a New Libretro Core

Cores are built externally in the LessUI-Cores repository. To add a core to LessUI:

  1. Add core to LessUI-Cores repository (core build system)
  2. Add core configuration to workspace/all/paks/Emus/cores.json
  3. Create core config file workspace/all/paks/Emus/configs/base/<core>/default.cfg
  4. Run ./scripts/generate-paks.sh all to generate platform paks
  5. Test on target hardware

See cores.md for details on how cores are distributed and loaded. See paks-architecture.md for pak generation system documentation.

Fixing a Bug

  1. Write a failing test first (if possible)
  2. Fix the bug
  3. Verify test passes
  4. Run make lint to check for issues

Updating Assets

LessUI uses a source + generated asset system for easy maintenance.

Source assets live in skeleton/SYSTEM/res-src/:

  • assets.png - UI sprite sheet (512×512)
  • installing.png, updating.png, bootlogo.png, charging.png - Boot screens (640×480)

To update assets:

# 1. Edit source file in skeleton/SYSTEM/res-src/
# 2. Regenerate all variants:
./scripts/generate-assets.sh
# 3. Commit both source and generated files

This generates 40+ variants (PNGs at different scales, BMPs for different platforms) automatically.

See skeleton/SYSTEM/res-src/README.md for detailed asset guidelines and ideal resolutions.

Troubleshooting

Docker Won't Start

Check Docker Desktop is running. Restart if needed.

Build Fails

Try cleaning:

make clean

Then rebuild:

make PLATFORM=miyoomini

Tests Fail

Tests run in Docker. Check test output carefully. Tests are strict about memory and undefined behavior.

Common issues:

  • Buffer too small
  • Uninitialized variables
  • Off-by-one errors

Platform Won't Boot

Check workspace/<platform>/install/boot.sh for errors. Boot scripts are platform-specific and finicky.

Enable verbose logging by editing boot script to redirect output:

./launcher.elf > /tmp/launcher.log 2>&1

Then check logs on device.

Resources

Getting Help

  • Check existing code for examples
  • Platform READMEs document hardware quirks
  • CLAUDE.md has detailed architecture notes
  • GitHub issues for bugs and questions