# m5unified-rs

Rust bindings for [M5Unified](https://github.com/m5stack/M5Unified), the
board support library used across M5Stack ESP32 devices.

The project publishes two crates:

- [`m5unified`](https://docs.rs/m5unified) - safe Rust API for common
  M5Unified display, button, microphone, speaker, IMU, touch, RTC, power, log,
  and SD-card operations.
- [`m5unified-sys`](https://docs.rs/m5unified-sys) - raw FFI declarations plus
  the C/C++ ESP-IDF component shim used by the safe crate.

The binding strategy is intentionally narrow: Rust calls a plain `extern "C"`
shim instead of trying to bind the full M5Unified C++ class surface directly.

## Install

For applications, depend on the safe wrapper:

```toml
[dependencies]
m5unified = "0.2"
```

Use `m5unified-sys` directly only when writing lower-level bindings or firmware
integration code that needs the raw C ABI.

## Quick Start

```rust
use m5unified::{colors, M5Unified};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut m5 = M5Unified::begin()?;

    m5.display.fill_screen(colors::BLACK);
    m5.display.set_text_size(2);
    m5.display.println("hello from Rust")?;

    loop {
        m5.update();
        if m5.buttons.a().was_pressed() {
            m5.display.println("Button A")?;
        }
        m5.delay_ms(16);
    }
}
```

## Target Support

On ESP-IDF targets, `m5unified-sys` declares the C ABI that is implemented by
the native shim in this repository. Firmware projects should include that shim
as an ESP-IDF component so the Rust crate links against the real M5Unified and
M5GFX libraries.

On non-ESP-IDF host targets, `m5unified-sys` provides no-op Rust stubs. This
keeps the safe wrapper and translated examples buildable in CI and on developer
machines without M5Stack hardware. Host stubs are for compile-time checking, not
hardware simulation.

## API Surface

The current wrapper covers the API used by the translated upstream examples:

- startup configuration through `M5UnifiedConfig` and `M5Unified::begin_with_config`
- display drawing, text, color, brightness, transactions, and multi-display access
- button press, release, hold, click, and click-count state
- microphone recording helpers and simple RMS calculation
- speaker tone, PCM, WAV, channel, and volume controls
- IMU acceleration, gyro, temperature, calibration, and NVS offsets
- touch points and touch detail state
- RTC date/time, power/battery, AXP2101 IRQ helpers, LED control, logging, and SD begin
- board identity, pin lookup, primary/log display selection, and touch-button sizing

This is not a complete M5Unified port yet. Missing APIs should be added through
the C ABI shim first, then wrapped by `m5unified`.

## Repository Layout

```text
crates/
  m5unified-sys/   raw bindings and native C/C++ shim
  m5unified/       safe Rust wrapper
examples/          host-checkable Rust ports of upstream M5Unified examples
firmware/          ESP-IDF Rust firmware package for hardware validation
docs/              example mapping, project plans, and release notes
```

## Examples

Rust translations and smoke ports of upstream M5Unified examples live in the
repository's `examples` workspace package. They are intentionally not published
as a crate.

```bash
bash scripts/check-host.sh
cargo run -p m5unified-examples --bin basic_displays
```

See the repository docs for the upstream-to-Rust example mapping and firmware
bring-up instructions.

## Firmware Bring-Up

The first ESP-IDF Rust firmware package lives at
`firmware/hello-display` in the repository. It is excluded from the host
workspace because it requires the esp-rs `xtensa-esp32s3-espidf` toolchain.

Install the esp-rs tools before building firmware:

```bash
cargo +stable install espup
espup install
. ~/export-esp.sh
cargo +stable install espflash
```

Then build and flash the sample firmware:

```bash
cd firmware/hello-display
cargo build --target xtensa-esp32s3-espidf
espflash flash --monitor target/xtensa-esp32s3-espidf/debug/m5unified-hello-display
```

Expected hardware behavior: the display shows `hello from rust`; Button A/B
presses change the screen.

## Release Checks

```bash
python3 tools/check_examples_manifest.py
python3 tools/check_no_sys_in_examples.py
bash scripts/check-host.sh
cargo package -p m5unified-sys
cargo publish -p m5unified-sys --dry-run
```

Publish `m5unified-sys` before `m5unified`, because the safe crate depends on
the exact sys crate version through crates.io. Package and dry-run `m5unified`
after the sys crate upload has propagated. See `docs/publishing.md` in the
repository for the full release checklist.

## License

Licensed under either MIT or Apache-2.0, at your option.
