Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,33 @@ and this project adheres to [Conventional Commits](https://www.conventionalcommi

## [Unreleased]

### Changed

- Remap AUX strobe switches: AUX7 3-way off → red/green → white, AUX8 momentary → white strobe at 80
- Add `strobe_split` field to `LedState` for position-light strobe mode

### Added

- Temporal dithering module (`src/dither.rs`): adds extra perceived bit depth to WS2812B LEDs by varying quantized output frame-to-frame faster than flicker fusion
- `DitherMode` enum with four modes: `Off`, `ErrorDiffusion` (smooth gradients), `Ordered` (Bayer 4x4, deterministic), `Hybrid` (error diffusion + correlated ordered for low brightness)
- 8.8 fixed-point gamma LUTs (3 x 256 entries, 1536 bytes flash) computed at compile time for high-precision gamma correction in the dithered path
- `SetDitherMode` and `SetDitherFps` BLE commands for runtime control of dithering
- `dither_mode` and `dither_fps` fields in BLE `StateResponse`
- Inner dither loop in LED task: animation renders at `fps` rate, strip refreshes at `dither_fps` rate (100–960 Hz) with different dither patterns between animation frames
- Dither state auto-reset on mode change, strobe activation, and BLE flash sequences
- Unit tests for dither algorithms (error diffusion convergence, ordered determinism, Fix16 gamma roundtrip)
- `DisplayTestPattern` BLE command: temporarily force a color + animation combo for a given duration, overriding FC flight mode patterns
- `CancelTestPattern` BLE command: stop a running test pattern immediately
- `test_active` field in BLE `StateResponse` (true when a test pattern is playing)
- RSSI-based TX link detection via MSP_ANALOG — strobe only activates when RSSI > 0 (replaces unreliable stick-center heuristic)
- `tx_linked` field exposed in BLE `StateResponse` for app display

### Removed

- Wi-Fi AP hotspot, HTTP web UI, and DHCP server (BLE is now the sole control interface)
- `embassy-net`, `smoltcp`, `edge-dhcp`, and `embedded-io` dependencies
- `wifi` and `coex` features from `esp-radio` (no longer needed without Wi-Fi)

### Added

- BLE Nordic UART Service (NUS) for app control via JSON protocol
Expand Down
101 changes: 0 additions & 101 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 1 addition & 22 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,6 @@ path = "./src/bin/main.rs"

[dependencies]
defmt = "0.3.10"
embassy-net = { version = "0.8.0", features = [
"dhcpv4",
"medium-ethernet",
"tcp",
"udp",
] }
embedded-io = "0.7.1"
embedded-io-async = "0.7.0"
esp-alloc = "0.9.0"
esp-hal = { version = "1.0.0", features = [
Expand All @@ -25,18 +18,6 @@ esp-hal = { version = "1.0.0", features = [
] }
panic-rtt-target = { version = "0.2.0", features = ["defmt"] }
rtt-target = { version = "0.6.1", features = ["defmt"] }
smoltcp = { version = "0.12.0", default-features = false, features = [
"medium-ethernet",
"multicast",
"proto-dhcpv4",
"proto-dns",
"proto-ipv4",
"socket-dns",
"socket-icmp",
"socket-raw",
"socket-tcp",
"socket-udp",
] }
bleps = { git = "https://github.com/bjoernQ/bleps", package = "bleps", rev = "a5148d8ae679e021b78f53fd33afb8bb35d0b62e", features = [
"async",
"macros",
Expand All @@ -56,10 +37,8 @@ esp-rtos = { version = "0.2.0", features = [
] }
esp-radio = { version = "0.17.0", features = [
"ble",
"coex",
"defmt",
"esp32c3",
"wifi",
"unstable",
] }
heapless = { version = "0.8.0", default-features = false, features = ["serde"] }
Expand All @@ -70,7 +49,7 @@ static_cell = { version = "2.1.0", features = ["nightly"] }
smart-leds = "0.4.0"
ws2812-spi = "0.5.1"
esp-bootloader-esp-idf = { version = "0.4.0", features = ["esp32c3"] }
edge-dhcp = { version = "0.7.0", features = ["io", "defmt"] }


[profile.dev]
# Rust debug is too slow.
Expand Down
34 changes: 32 additions & 2 deletions FLUTTER_BLE_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This guide is for building a Flutter companion app that controls the AirLED ESP3

## Architecture Overview

The device runs on an ESP32-C3 (XIAO form factor) and exposes a **Nordic UART Service (NUS)** over BLE. Communication is newline-delimited JSON over a serial-like BLE pipe. The device also runs a Wi-Fi AP with HTTP control as a fallback, but BLE is the primary interface for the app.
The device runs on an ESP32-C3 (XIAO form factor) and exposes a **Nordic UART Service (NUS)** over BLE. Communication is newline-delimited JSON over a serial-like BLE pipe. BLE is the primary and only control interface for the app.

## BLE Connection

Expand Down Expand Up @@ -219,6 +219,32 @@ Per-frame amplitude decay percentage. Only applies in ripple mode.

- `value`: `u8` (clamped 90–99), default **97**

### DisplayTestPattern

Temporarily force a color + animation combo for a given duration, overriding FC flight mode patterns.

```json
{"DisplayTestPattern":{"color":"rainbow","anim":"ripple","duration_ms":5000}}
```

- `color`: string — any valid color mode key (see SetColorMode)
- `anim`: string — any valid animation mode key (see SetAnimMode)
- `duration_ms`: `u16` (1–65535) — how long to display the test pattern in milliseconds

Returns `ok\n` on success, or `err:unknown_color_mode\n` / `err:unknown_anim_mode\n` on invalid values.

The test pattern overrides FC flight mode displays but not AUX strobe or BLE flash indicators. When the duration expires, the device reverts to normal behavior and pushes a state update.

### CancelTestPattern

Stop a running test pattern immediately and revert to normal behavior.

```json
{"CancelTestPattern":null}
```

Returns `ok\n`. Safe to send even when no test pattern is active.

## StateResponse (device → app)

Full JSON state snapshot. Approximately 250 bytes serialized.
Expand All @@ -242,7 +268,9 @@ Full JSON state snapshot. Approximately 250 bytes serialized.
"ripple_width": 190,
"ripple_decay": 97,
"fc_connected": false,
"flight_mode": "arming_forbidden"
"flight_mode": "arming_forbidden",
"tx_linked": false,
"test_active": false
}
```

Expand All @@ -268,6 +296,8 @@ Full JSON state snapshot. Approximately 250 bytes serialized.
| `ripple_decay` | int | 90–99 | Ripple decay % |
| `fc_connected` | bool | | Flight controller connected |
| `flight_mode` | string | see below | Current flight mode |
| `tx_linked` | bool | | RC transmitter link active (RSSI > 0) |
| `test_active` | bool | | A BLE test pattern is currently playing |

### Flight modes

Expand Down
Loading
Loading