# KV-TrimUI Full Technical Handbook & Core Rust Engine Architecture > Complete engineering reference for building high-performance 60 FPS native software on TrimUI Smart Pro & Brick Pro handheld consoles. --- ## 1. Hardware Architecture & System Environment ### 1.1 Hardware Specifications - **Application Processor**: Allwinner A133plus Quad-Core ARM Cortex-A53 @ 1.8GHz. - **Instruction Set**: 64-bit ARMv8-A (`aarch64`). - **GPU**: Imagination PowerVR GE8300 (OpenGLES 2.0 / 3.2 support via proprietary Mali/PVR blobs). - **RAM**: 1 GB LPDDR4 @ 1600MHz (Single channel, shared with GPU). - **Display**: 4.96-inch IPS Panel, 1280x720 pixels (16:9 widescreen), 60Hz native refresh rate. - **Internal Storage**: eMMC / SPI flash containing U-Boot and base kernel/rootfs partitions. - **Removable Storage**: MicroSD Card slot mounted persistently at `/mnt/SDCARD/`. - **Audio Output**: Dual front-facing stereo speakers + 3.5mm stereo headphone jack, driven by ALSA SoC audio codec. - **Battery**: 5000 mAh Li-Po with AXP717 PMIC charging controller. ### 1.2 OS Environment & Critical Constraints 1. **Linux Kernel**: Stock OS runs Linux Kernel 4.9 LTS. 2. **Absence of Display Servers**: There is NO X11, NO Wayland, and NO Desktop Environment. Software that attempts to connect to `DISPLAY=:0` or `WAYLAND_DISPLAY` will abort immediately. 3. **Display Driver**: Hardware exposes `/dev/fb0`. Standard resolution is 1280x720 with 32 bits per pixel (4 bytes per pixel). Line length (stride) is 5120 bytes (1280 * 4). Total buffer size is 3,686,400 bytes (1280 * 720 * 4). 4. **GLIBC Incompatibility Trap**: The rootfs glibc version is legacy (~2.28 - 2.31). If you compile a Rust binary targeting `aarch64-unknown-linux-gnu`, executing it on device will fail with `/lib/libc.so.6: version 'GLIBC_2.34' not found`. - **MANDATORY SOLUTION**: Always compile with `--target aarch64-unknown-linux-musl`. The `musl` C runtime statically links all standard library routines into a standalone ELF binary with zero shared-library runtime dependencies. --- ## 2. Core Engine 1: Direct Framebuffer (`/dev/fb0`) Rendering ### 2.1 Color Representation On TrimUI Allwinner FB drivers, pixel format is 32-bit ARGB/XRGB (or BGRA in Little-Endian byte order): ``` Pixel: [Blue: 8 bits] [Green: 8 bits] [Red: 8 bits] [Alpha/Padding: 8 bits] u32 representation: (A << 24) | (R << 16) | (G << 8) | B ``` ### 2.2 Complete Minimal Framebuffer Rust Implementation ```rust use std::fs::OpenOptions; use std::os::unix::fs::OpenOptionsExt; use std::os::unix::io::AsRawFd; pub const FB_WIDTH: usize = 1280; pub const FB_HEIGHT: usize = 720; pub const FB_STRIDE: usize = FB_WIDTH * 4; pub const FB_TOTAL_BYTES: usize = FB_STRIDE * FB_HEIGHT; pub struct Framebuffer { fb_mem: *mut u8, back_buffer: Vec, fd: std::fs::File, } impl Framebuffer { pub fn new() -> Result { let file = OpenOptions::new() .read(true) .write(true) .open("/dev/fb0")?; let fb_mem = unsafe { libc::mmap( std::ptr::null_mut(), FB_TOTAL_BYTES, libc::PROT_READ | libc::PROT_WRITE, libc::MAP_SHARED, file.as_raw_fd(), 0, ) }; if fb_mem == libc::MAP_FAILED { return Err(std::io::Error::last_os_error()); } Ok(Self { fb_mem: fb_mem as *mut u8, back_buffer: vec![0u32; FB_WIDTH * FB_HEIGHT], fd: file, }) } #[inline(always)] pub fn draw_pixel(&mut self, x: usize, y: usize, color: u32) { if x < FB_WIDTH && y < FB_HEIGHT { self.back_buffer[y * FB_WIDTH + x] = color; } } pub fn clear(&mut self, color: u32) { self.back_buffer.fill(color); } pub fn draw_rect(&mut self, x: usize, y: usize, w: usize, h: usize, color: u32) { let x_end = (x + w).min(FB_WIDTH); let y_end = (y + h).min(FB_HEIGHT); for cy in y..y_end { let row_offset = cy * FB_WIDTH; for cx in x..x_end { self.back_buffer[row_offset + cx] = color; } } } /// Blits the back-buffer to /dev/fb0 in a single memory transfer pub fn flip(&mut self) { unsafe { std::ptr::copy_nonoverlapping( self.back_buffer.as_ptr() as *const u8, self.fb_mem, FB_TOTAL_BYTES, ); } } } impl Drop for Framebuffer { fn drop(&mut self) { unsafe { libc::munmap(self.fb_mem as *mut libc::c_void, FB_TOTAL_BYTES); } } } ``` --- ## 3. Core Engine 2: Linux Evdev Gamepad Input Subsystem TrimUI controls are surfaced as standard Linux input events under `/dev/input/event0`, `/dev/input/event1`, or `/dev/input/event2`. ### 3.1 Button Keycode Mapping Table | Hardware Control | Linux Evdev Constant | Keycode (Decimal) | Event Type | Description | | :--- | :--- | :--- | :--- | :--- | | **A Button** | `BTN_SOUTH` / `KEY_A` | `304` | `EV_KEY` (0x01) | Primary Confirm / Select | | **B Button** | `BTN_EAST` / `KEY_B` | `305` | `EV_KEY` (0x01) | Cancel / Back | | **X Button** | `BTN_NORTH` / `KEY_X` | `307` | `EV_KEY` (0x01) | Alternate Action / Menu | | **Y Button** | `BTN_WEST` / `KEY_Y` | `308` | `EV_KEY` (0x01) | Context Action / Toggle | | **L1 Bumper** | `BTN_TL` | `310` | `EV_KEY` (0x01) | Left Shoulder Button | | **R1 Bumper** | `BTN_TR` | `311` | `EV_KEY` (0x01) | Right Shoulder Button | | **L2 Trigger** | `BTN_TL2` or `ABS_Z` | `312` or `2` | `EV_KEY` or `EV_ABS` | Left Analog/Digital Trigger | | **R2 Trigger** | `BTN_TR2` or `ABS_RZ` | `313` or `5` | `EV_KEY` or `EV_ABS` | Right Analog/Digital Trigger | | **SELECT** | `BTN_SELECT` | `314` | `EV_KEY` (0x01) | Select / Settings | | **START** | `BTN_START` | `315` | `EV_KEY` (0x01) | Start / Pause | | **L3 (Left Stick Click)** | `BTN_THUMBL` | `317` | `EV_KEY` (0x01) | Left Stick Button | | **R3 (Right Stick Click)**| `BTN_THUMBR` | `318` | `EV_KEY` (0x01) | Right Stick Button | | **D-Pad UP** | `KEY_UP` or `ABS_HAT0Y == -1` | `103` or `17` | `EV_KEY` or `EV_ABS` | D-Pad Navigation Up | | **D-Pad DOWN** | `KEY_DOWN` or `ABS_HAT0Y == 1` | `108` or `17` | `EV_KEY` or `EV_ABS` | D-Pad Navigation Down | | **D-Pad LEFT** | `KEY_LEFT` or `ABS_HAT0X == -1`| `105` or `16` | `EV_KEY` or `EV_ABS` | D-Pad Navigation Left | | **D-Pad RIGHT** | `KEY_RIGHT` or `ABS_HAT0X == 1`| `106` or `16` | `EV_KEY` or `EV_ABS` | D-Pad Navigation Right | | **Left Stick X/Y** | `ABS_X` / `ABS_Y` | `0` / `1` | `EV_ABS` (0x03) | Value range: -32768 to 32767 | | **Right Stick X/Y**| `ABS_RX` / `ABS_RY` | `3` / `4` | `EV_ABS` (0x03) | Value range: -32768 to 32767 | ### 3.2 Non-Blocking Evdev Polling Pattern in Rust ```rust use std::fs::File; use std::os::unix::fs::OpenOptionsExt; use std::os::unix::io::AsRawFd; #[repr(C)] struct InputEvent { tv_sec: usize, tv_usec: usize, type_: u16, code: u16, value: i32, } pub struct GamepadState { pub a: bool, pub b: bool, pub x: bool, pub y: bool, pub up: bool, pub down: bool, pub left: bool, pub right: bool, pub l1: bool, pub r1: bool, pub start: bool, pub select: bool, } pub fn poll_gamepad(fd: &File, state: &mut GamepadState) { let mut raw_events = [InputEvent { tv_sec: 0, tv_usec: 0, type_: 0, code: 0, value: 0 }; 16]; let bytes_read = unsafe { libc::read( fd.as_raw_fd(), raw_events.as_mut_ptr() as *mut libc::c_void, std::mem::size_of_val(&raw_events), ) }; if bytes_read <= 0 { return; } let count = bytes_read as usize / std::mem::size_of::(); for ev in &raw_events[..count] { if ev.type_ == 1 { // EV_KEY let pressed = ev.value > 0; match ev.code { 304 => state.a = pressed, 305 => state.b = pressed, 307 => state.x = pressed, 308 => state.y = pressed, 103 => state.up = pressed, 108 => state.down = pressed, 105 => state.left = pressed, 106 => state.right = pressed, 310 => state.l1 = pressed, 311 => state.r1 = pressed, 315 => state.start = pressed, 314 => state.select = pressed, _ => {} } } } } ``` --- ## 4. Core Engine 3: Typography & TrueType Rendering with `fontdue` To achieve fast, high-quality typography without heavy dynamic libraries (FreeType, Cairo), we employ `fontdue`, an ultra-fast, pure Rust TrueType/OpenType font rasterizer: ```rust use fontdue::{Font, FontSettings}; pub struct FontRenderer { font: Font, } impl FontRenderer { pub fn new(ttf_bytes: &[u8]) -> Result { let font = Font::from_bytes(ttf_bytes, FontSettings::default())?; Ok(Self { font }) } pub fn draw_text(&self, fb: &mut Framebuffer, text: &str, x: usize, y: usize, size_px: f32, color: u32) { let mut cur_x = x as f32; let r = ((color >> 16) & 0xFF) as f32; let g = ((color >> 8) & 0xFF) as f32; let b = (color & 0xFF) as f32; for ch in text.chars() { let (metrics, bitmap) = self.font.rasterize(ch, size_px); let gx = (cur_x + metrics.xmin as f32) as usize; let gy = (y as f32 + size_px - metrics.height as f32 - metrics.ymin as f32) as usize; for row in 0..metrics.height { for col in 0..metrics.width { let alpha = bitmap[row * metrics.width + col]; if alpha > 0 { let px = gx + col; let py = gy + row; if px < FB_WIDTH && py < FB_HEIGHT { let a_factor = alpha as f32 / 255.0; let blended = (((r * a_factor) as u32) << 16) | (((g * a_factor) as u32) << 8) | ((b * a_factor) as u32); fb.draw_pixel(px, py, blended); } } } } cur_x += metrics.advance_width; } } } ``` --- ## 5. Application Packaging & System Lifecycle Standards Each TrimUI application must reside in `/mnt/SDCARD/Apps//` and provide 3 essential files: ### 5.1 Directory Structure ``` /mnt/SDCARD/Apps// ├── config.json # App metadata, UI label, and accent theme color ├── launch.sh # Shell wrapper handling MainUI pause/resume and execution ├── icon.png # App icon (120x120 or 256x256 PNG) └── bin/ └── # Cross-compiled aarch64-unknown-linux-musl binary ``` ### 5.2 Canonical `config.json` ```json { "label": "My App Name", "icon": "icon.png", "themecolor": "#3b82f6", "description": "High performance Rust application for TrimUI Smart Pro" } ``` ### 5.3 Canonical `launch.sh` (Handling Process Lifecycle) ```bash #!/bin/sh APP_DIR="$(cd "$(dirname "$0")" && pwd)" cd "$APP_DIR" # 1. Stop MainUI to free /dev/fb0 and /dev/input/event nodes killall -STOP MainUI 2>/dev/null || true # 2. Configure system environment export LD_LIBRARY_PATH="$APP_DIR/lib:/usr/lib:/lib:$LD_LIBRARY_PATH" export PATH="$APP_DIR/bin:$PATH" # 3. Launch native Rust binary ./bin/my-app # 4. Resume MainUI when app terminates killall -CONT MainUI 2>/dev/null || /usr/trimui/bin/MainUI & ``` --- ## 6. Cross-Compilation & Build Toolchain ### 6.1 `Cargo.toml` Release Profile Configuration Add these settings to produce sub-megabyte, zero-dependency binaries: ```toml [profile.release] opt-level = "z" # Optimize for size lto = true # Link-Time Optimization codegen-units = 1 # Maximize optimization panic = "abort" # Remove stack unwinding bloat strip = true # Strip symbols and debug info ``` ### 6.2 Host Setup & Build Commands ```bash # Add ARM64 musl target rustup target add aarch64-unknown-linux-musl # Compile with LLVM lld linker (installed by default with Rust) RUSTFLAGS="-C linker=rust-lld" cargo build \ --target aarch64-unknown-linux-musl \ --release ``` --- ## 7. Automatic Publishing & Ecosystem Integration Once compiled, you can publish and distribute software across all TrimUI consoles using our automated ecosystem tool: ```bash # Auto-package ZIP, generate OTA JSON, sync catalog, and deploy to VPS: pnpm app:publish --version --deploy ``` - Available instantly in **KV-File** (`http://:4545`) with 1-Tap wireless install. - Automatically detected by **KV-Launcher** dynamic scanner and rendered on the 60 FPS PS5 Carousel!