diff --git a/firmware/zeroclaw-esp32-ui/Cargo.toml b/firmware/zeroclaw-esp32-ui/Cargo.toml index d42f7c4..5c7ddcc 100644 --- a/firmware/zeroclaw-esp32-ui/Cargo.toml +++ b/firmware/zeroclaw-esp32-ui/Cargo.toml @@ -7,10 +7,9 @@ description = "ZeroClaw ESP32 UI firmware with Slint - Graphical interface for A authors = ["ZeroClaw Team"] [dependencies] -# ESP-IDF framework +anyhow = "1.0" esp-idf-svc = "0.48" log = { version = "0.4", default-features = false } -anyhow = "1.0" # Slint UI - MCU optimized slint = { version = "1.10", default-features = false, features = [ @@ -19,41 +18,13 @@ slint = { version = "1.10", default-features = false, features = [ "renderer-software", ] } -# Display drivers -mipidsi = { version = "0.9", features = ["batch"] } -display-interface-spi = "0.5" -embedded-graphics = "0.8" - - -# Serialization for communication -serde = { version = "1.0", default-features = false, features = ["derive"] } -serde_json = { version = "1.0", default-features = false, features = ["alloc"] } - -# Async support -embassy-sync = { version = "0.6", features = ["defmt"] } -embassy-futures = "0.1" -embassy-time = { version = "0.1", features = ["tick-hz-100", "defmt"] } - -# WiFi networking -embedded-svc = "0.28" - -# Capacitive touch driver (FT6X36) -ft6x36 = "0.2" - -# I2C for touch controller -esp-idf-hal = "0.43" - -# Utilities -heapless = "0.8" -nb = "1.1" - [build-dependencies] embuild = { version = "0.31", features = ["elf"] } slint-build = "1.10" [features] default = ["std", "display-st7789"] -std = ["esp-idf-svc/std", "serde/std", "serde_json/std"] +std = ["esp-idf-svc/std"] # Display selection (choose one) display-st7789 = [] # 320x240 or 135x240 diff --git a/firmware/zeroclaw-esp32-ui/README.md b/firmware/zeroclaw-esp32-ui/README.md index 50e7347..ffba119 100644 --- a/firmware/zeroclaw-esp32-ui/README.md +++ b/firmware/zeroclaw-esp32-ui/README.md @@ -1,193 +1,106 @@ # ZeroClaw ESP32 UI Firmware -Slint-based graphical interface for ZeroClaw AI assistant on ESP32. +Slint-based graphical UI firmware scaffold for ZeroClaw edge scenarios on ESP32. + +## Scope of This Crate + +This crate intentionally provides a **minimal, bootable UI scaffold**: + +- Initializes ESP-IDF logging/runtime patches +- Compiles and runs a small Slint UI (`MainWindow`) +- Keeps display and touch feature flags available for incremental driver integration + +What this crate **does not** do yet: + +- No full chat runtime integration +- No production display/touch driver wiring in `src/main.rs` +- No Wi-Fi/BLE transport logic ## Features -- **Modern UI**: Declarative interface built with Slint UI framework -- **Touch Support**: Compatible with resistive (XPT2046) and capacitive (FT6X36) touch panels -- **Display Options**: Support for ST7789, ILI9341, and SSD1306 displays -- **Connectivity**: WiFi and Bluetooth Low Energy support -- **Memory Efficient**: Optimized for ESP32's limited RAM (~520KB) - -## Hardware Requirements - -### Recommended: ESP32-S3 -- **SoC**: ESP32-S3 (Xtensa LX7 dual-core, 240MHz) -- **RAM**: 512KB SRAM + 8MB PSRAM (optional but recommended) -- **Display**: 2.8" 320x240 TFT LCD (ST7789 or ILI9341) -- **Touch**: XPT2046 resistive or FT6X36 capacitive -- **Storage**: 4MB+ Flash - -### Alternative: ESP32-C3 -- **SoC**: ESP32-C3 (RISC-V single-core, 160MHz) -- **RAM**: 400KB SRAM -- **Display**: 1.14" 135x240 TFT (ST7789) -- **Note**: Limited to simpler UI due to RAM constraints +- **Slint UI scaffold** suitable for MCU-oriented iteration +- **Display feature flags** for ST7789, ILI9341, SSD1306 +- **Touch feature flags** for XPT2046 and FT6X36 integration planning +- **ESP-IDF baseline** for embedded target builds ## Project Structure -``` +```text firmware/zeroclaw-esp32-ui/ -├── Cargo.toml # Rust dependencies -├── build.rs # Build script for Slint compilation +├── Cargo.toml # Rust package and feature flags +├── build.rs # Slint compilation hook ├── .cargo/ -│ └── config.toml # Cross-compilation settings +│ └── config.toml # Cross-compilation defaults ├── ui/ │ └── main.slint # Slint UI definition └── src/ - └── main.rs # Application entry point + └── main.rs # Firmware entry point ``` ## Prerequisites -1. **Rust toolchain with ESP32 support**: +1. **ESP Rust toolchain** ```bash cargo install espup espup install source ~/export-esp.sh ``` -2. **Additional tools**: +2. **Flashing tools** ```bash cargo install espflash cargo-espflash ``` -3. **Hardware setup**: - - Connect display to SPI pins (see pin configuration below) - - Ensure proper power supply (3.3V logic level) +## Build and Flash -## Pin Configuration +### Default target (ESP32-C3, from `.cargo/config.toml`) -Default pin mapping for ESP32-S3 with ST7789 display and FT6X36 capacitive touch: - -### Display (SPI) - -| Function | GPIO Pin | Description | -|----------|---------|-------------| -| SPI SCK | GPIO 6 | SPI Clock | -| SPI MOSI | GPIO 7 | SPI Data Out | -| SPI MISO | GPIO 8 | SPI Data In (optional) | -| SPI CS | GPIO 10 | Chip Select | -| DC | GPIO 4 | Data/Command | -| RST | GPIO 3 | Reset | -| Backlight| GPIO 5 | Display backlight | - -### Touch Controller (I2C) - -| Function | GPIO Pin | Description | -|----------|---------|-------------| -| I2C SDA | GPIO 1 | I2C Data | -| I2C SCL | GPIO 2 | I2C Clock | -| INT | GPIO 11 | Touch interrupt | - -### Hardware Connections - -``` -ESP32-S3 ST7789 Display FT6X36 Touch ------------ --------------- ------------- -GPIO 6 ──────────► SCK -GPIO 7 ──────────► MOSI -GPIO 10 ──────────► CS -GPIO 4 ──────────► DC -GPIO 3 ──────────► RST -GPIO 5 ──────────► BACKLIGHT (via resistor) - -GPIO 1 ──────────► SDA -GPIO 2 ──────────► SCL -GPIO 11 ◄────────── INT -``` - -**Note**: Use 3.3V for power. ST7789 typically requires 3.3V logic level. - -## Building - -### Standard build for ESP32-S3: ```bash cd firmware/zeroclaw-esp32-ui cargo build --release -``` - -### Flash to device: -```bash cargo espflash flash --release --monitor ``` -### Build for ESP32-C3 (RISC-V): +### Build for ESP32-S3 (override target) + ```bash -rustup target add riscv32imc-esp-espidf -cargo build --release --target riscv32imc-esp-espidf +cargo build --release --target xtensa-esp32s3-espidf ``` -### Feature flags: +## Feature Flags + ```bash -# Use ILI9341 display instead of ST7789 +# Switch display profile cargo build --release --features display-ili9341 -# Enable WiFi support -cargo build --release --features wifi - -# Enable touch support -cargo build --release --features touch-xpt2046 +# Enable planned touch profile +cargo build --release --features touch-ft6x36 ``` -## UI Design +## UI Layout -The interface is defined in `ui/main.slint` with the following components: +The current `ui/main.slint` defines: -- **StatusBar**: Shows connection status and app title -- **MessageList**: Displays conversation history -- **InputBar**: Text input with send button -- **MainWindow**: Root container with vertical layout +- `StatusBar` +- `MessageList` +- `InputBar` +- `MainWindow` -### Customizing the UI +These components are placeholders to keep future hardware integration incremental and low-risk. -Edit `ui/main.slint` and rebuild: -```bash -cargo build --release -``` +## Next Integration Steps -The build script automatically compiles Slint files. - -## Memory Optimization - -For ESP32 (non-S3) with limited RAM: - -1. Reduce display buffer size in `main.rs`: - ```rust - const DISPLAY_WIDTH: usize = 240; - const DISPLAY_HEIGHT: usize = 135; - ``` - -2. Use smaller font sizes in Slint UI - -3. Enable release optimizations (already in Cargo.toml): - - `opt-level = "s"` (optimize for size) - - `lto = true` (link-time optimization) - -## Troubleshooting - -### Display shows garbage -- Check SPI connections and pin mapping -- Verify display orientation in `Builder::with_orientation()` -- Try different baud rates (26MHz is default) - -### Out of memory -- Reduce Slint window size -- Disable unused features -- Consider ESP32-S3 with PSRAM - -### Touch not working -- Verify touch controller is properly wired -- Check I2C/SPI address configuration -- Ensure interrupt pin is correctly connected +1. Wire real display driver initialization in `src/main.rs` +2. Attach touch input events to Slint callbacks +3. Connect UI state with ZeroClaw edge/runtime messaging +4. Add board-specific pin maps with explicit target profiles ## License -MIT - See root LICENSE file +MIT - See root `LICENSE` ## References - [Slint ESP32 Documentation](https://slint.dev/esp32) - [ESP-IDF Rust Book](https://esp-rs.github.io/book/) -- [ZeroClaw Hardware Design](../docs/hardware-peripherals-design.md) +- [ZeroClaw Hardware Design](../../docs/hardware-peripherals-design.md) diff --git a/firmware/zeroclaw-esp32-ui/src/main.rs b/firmware/zeroclaw-esp32-ui/src/main.rs new file mode 100644 index 0000000..6db084e --- /dev/null +++ b/firmware/zeroclaw-esp32-ui/src/main.rs @@ -0,0 +1,22 @@ +//! ZeroClaw ESP32 UI firmware scaffold. +//! +//! This binary initializes ESP-IDF, boots a minimal Slint UI, and keeps +//! architecture boundaries explicit so hardware integrations can be added +//! incrementally. + +use anyhow::Context; +use log::info; + +slint::include_modules!(); + +fn main() -> anyhow::Result<()> { + esp_idf_svc::sys::link_patches(); + esp_idf_svc::log::EspLogger::initialize_default(); + + info!("Starting ZeroClaw ESP32 UI scaffold"); + + let window = MainWindow::new().context("failed to create MainWindow")?; + window.run().context("MainWindow event loop failed")?; + + Ok(()) +} diff --git a/firmware/zeroclaw-esp32-ui/ui/main.slint b/firmware/zeroclaw-esp32-ui/ui/main.slint new file mode 100644 index 0000000..f2815b3 --- /dev/null +++ b/firmware/zeroclaw-esp32-ui/ui/main.slint @@ -0,0 +1,83 @@ +component StatusBar inherits Rectangle { + in property title_text: "ZeroClaw ESP32 UI"; + in property status_text: "disconnected"; + + height: 32px; + background: #1f2937; + border-radius: 6px; + + HorizontalLayout { + padding: 8px; + + Text { + text: root.title_text; + color: #e5e7eb; + font-size: 14px; + vertical-alignment: center; + } + + Text { + text: root.status_text; + color: #93c5fd; + font-size: 12px; + horizontal-alignment: right; + vertical-alignment: center; + } + } +} + +component MessageList inherits Rectangle { + in property message_text: "UI scaffold is running"; + + background: #0f172a; + border-radius: 6px; + border-color: #334155; + border-width: 1px; + + Text { + text: root.message_text; + color: #cbd5e1; + horizontal-alignment: center; + vertical-alignment: center; + } +} + +component InputBar inherits Rectangle { + in property hint_text: "Touch input integration pending"; + + height: 36px; + background: #1e293b; + border-radius: 6px; + + Text { + text: root.hint_text; + color: #e2e8f0; + horizontal-alignment: center; + vertical-alignment: center; + font-size: 12px; + } +} + +export component MainWindow inherits Window { + width: 320px; + height: 240px; + background: #020617; + + VerticalLayout { + padding: 10px; + spacing: 10px; + + StatusBar { + title_text: "ZeroClaw Edge UI"; + status_text: "booting"; + } + + MessageList { + message_text: "Display/touch drivers can be wired here"; + } + + InputBar { + hint_text: "Use touch-xpt2046 or touch-ft6x36 feature later"; + } + } +}