Skip to content
Merged

Dev #129

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
28955fc
chore: sync dev with main (pull v1.4.0)
anarchyysm Aug 17, 2026
9661c3d
chore(config): PSRAM ext-BSS, USB-MSC, image decoders, -O2 build
lthiagovs Aug 18, 2026
c87c6e9
fix(mesh): stop the Meshtastic/MeshCore phone-app connect crashes
lthiagovs Aug 18, 2026
a2de548
perf(mem): move large static UI/app buffers to PSRAM (EXT_RAM_BSS_ATTR)
lthiagovs Aug 18, 2026
645203b
perf(render): double buffering + larger strip + full-screen takeover …
lthiagovs Aug 18, 2026
abc3591
refactor(assets): make the image decoder color-format agnostic
lthiagovs Aug 18, 2026
6dc2066
feat(games): Game Boy (DMG) emulator + ROM picker
lthiagovs Aug 18, 2026
e91d0da
feat(images): immersive image / GIF viewer
lthiagovs Aug 18, 2026
590c21e
feat(video): MP4 player + media thumbnails
lthiagovs Aug 18, 2026
1277d12
feat(audio): MP3 player + ID3 metadata; cross-player playlist nav
lthiagovs Aug 18, 2026
e29f52d
feat(storage): USB Mass Storage — expose the SD as a USB drive
lthiagovs Aug 18, 2026
1adc348
feat(ui): Home/menu navigation affordances
lthiagovs Aug 18, 2026
c3d294d
refactor(ui): thread-safe cross-thread async scheduling (ui_async_call)
lthiagovs Aug 18, 2026
a897595
fix(radio): demote SX1262 RX-error hot-path logs; stop needless RX re…
lthiagovs Aug 18, 2026
694ca59
refactor(ui): semantic theme colors
lthiagovs Aug 18, 2026
1bf4b3c
fix(radio): shared SPI3 bus lock between SX1262 and ST7789
lthiagovs Aug 18, 2026
43ccd75
fix(mesh): show BLE pairing PIN and gate "linked" on subscribe
lthiagovs Aug 18, 2026
4e8285b
chore(assets): add game menu icons (breakout, flappy, gameboy, pet, s…
lthiagovs Aug 18, 2026
2f1b819
refactor(gameboy): move the emulator component under Applications
lthiagovs Aug 18, 2026
5647297
fix(storage): create parent dir for SD writes, not the file path
anarchyysm Aug 19, 2026
a9bac7f
refactor(wifi): route ap_scanner through wifi_service for clean SSIDs
anarchyysm Aug 19, 2026
f1511d8
feat(sniffer): save fragmented pcap with radiotap to SD card
anarchyysm Aug 19, 2026
130533a
fix(bridge): give the BLE lifecycle commands enough SPI timeout
lthiagovs Aug 18, 2026
5b05467
fix(radio): harden SX1262 RX against errored packets and flaky SPI3
lthiagovs Aug 18, 2026
9433574
fix(ui): async-delete the keyboard to avoid a self-delete use-after-free
lthiagovs Aug 18, 2026
c3863eb
chore(build): track dependencies.lock for reproducible builds
lthiagovs Aug 18, 2026
6876fc4
fix(radio): retry the SX1262 bring-up until it lands in STDBY_RC
lthiagovs Aug 18, 2026
420ae41
fix(ui): stop coverflow opacity animation from leaking local styles (…
lthiagovs Aug 18, 2026
84e23bc
fix(display): drive SPI3 SCLK/MOSI harder to stop radio-EMI garbling
lthiagovs Aug 18, 2026
9582ecf
fix(ui): make the shared chrome, menu and modal rotation-aware
lthiagovs Aug 18, 2026
5274998
feat(ui): apply screen rotation live by rebuilding the active screen
lthiagovs Aug 18, 2026
0d2ac8a
feat(ui): rotate d-pad input to match the screen in landscape
lthiagovs Aug 19, 2026
24d39fe
fix(ui): make per-screen layouts rotation-aware (phase 3-4)
lthiagovs Aug 19, 2026
fef7fc2
fix(ui): flip the landscape d-pad remap direction
lthiagovs Aug 19, 2026
5c43a3a
fix(ui): make the onboarding wizard rotation-aware
lthiagovs Aug 19, 2026
6190730
fix(ui): make the dropdown rotation-aware (nav + height)
lthiagovs Aug 19, 2026
b0e9c5d
fix(ui): fit the wifi channel-analysis spectrum to landscape
lthiagovs Aug 19, 2026
fc3ce61
fix(ui): clamp per-screen layouts to landscape
lthiagovs Aug 19, 2026
80715fb
fix(ui): image viewer loading card, fit-to-screen and psram decode
lthiagovs Aug 19, 2026
5caa38f
fix(ui): remove home wallpaper
lthiagovs Aug 19, 2026
01ddba6
fix(lora): sx1262 and meshcore rx robustness
lthiagovs Aug 19, 2026
e242689
fix(wifi): drop blocking led in c5 deauther and evil-twin hot paths
lthiagovs Aug 19, 2026
f97b30b
fix(ui): prevent tutorial double-click passthrough
lthiagovs Aug 19, 2026
e05afb0
fix(ui): drop wifi toggle and mock networks from connection settings
lthiagovs Aug 19, 2026
05e3df4
feat(ui): c5 update progress modal and imu entry
lthiagovs Aug 19, 2026
6f97fc5
fix(ui): led notify config
lthiagovs Aug 19, 2026
24b2051
fix(console): firstboot arms next-reset flag without wiping
lthiagovs Aug 19, 2026
c3cb8a4
fix(ui): resolve theme by name and central input pump
lthiagovs Aug 19, 2026
7523634
fix(lora): chat ui
lthiagovs Aug 19, 2026
34b30e3
chore(time): sys_time adjustment
lthiagovs Aug 19, 2026
d2f622c
fix(nfc): nfc read ui
lthiagovs Aug 19, 2026
adefb20
chore(build): add gameboy
lthiagovs Aug 19, 2026
07c16dd
fix(usb): advertise MSC only in mass-storage mode to stop TinyUSB cra…
anarchyysm Aug 19, 2026
c39f18e
chore: ignore ESP-IDF dependencies.lock
anarchyysm Aug 19, 2026
2e7b397
perf(badusb): pace HID reports by tud_hid_ready for max drop-free typ…
anarchyysm Aug 19, 2026
2052ff5
feat(badusb): add Amiga ASCII art payload; map grave/backslash/apostr…
anarchyysm Aug 19, 2026
ebf99fa
fix(badusb): correct ABNT2 apostrophe and add backtick so ASCII art r…
anarchyysm Aug 19, 2026
f2f2bd2
docs: require short pertinent comments in CLAUDE.md and trim verbose …
anarchyysm Aug 19, 2026
ca37977
fix(badusb): raise HID ready timeout to survive host stalls so HOME i…
anarchyysm Aug 19, 2026
43dcd2b
fix(badusb): END before ENTER in amiga payload to stop auto-indent ac…
anarchyysm Aug 19, 2026
d30ea28
feat(badusb): scan SD payload subfolders recursively, list all in one…
anarchyysm Aug 19, 2026
63fc412
feat(badusb): complete ABNT2 coverage with missing symbols and full a…
anarchyysm Aug 19, 2026
f74f5c5
feat(badusb): accept SUPER as an alias for the GUI modifier
anarchyysm Aug 19, 2026
0503aef
docs(spi_bridge): document 7-byte CRC framing, protocol v2, screen ca…
anarchyysm Aug 19, 2026
21f7e20
docs(c5_flasher): document transport selector, SD streaming and ROM d…
anarchyysm Aug 19, 2026
3c0af06
docs(spi): add SPI_DEVICE_BRIDGE and note legacy CC1101 label
anarchyysm Aug 19, 2026
ef1a382
docs(bridge_manager): add link-manager and version-check documentation
anarchyysm Aug 19, 2026
8c91229
docs(wifi): rewrite P4 as SPI-bridge proxy and add C5 busy/power-save…
anarchyysm Aug 19, 2026
054da1a
docs(bluetooth): document sniffer, tracker and connect APIs
anarchyysm Aug 19, 2026
3cf8dea
docs(tusb_desc): document HID+CDC+MSC composite and runtime MSC exposure
anarchyysm Aug 19, 2026
8f15d99
docs(bad_usb): document SUPER alias, HID-ready pacing and full ABNT2 …
anarchyysm Aug 19, 2026
c14f72b
docs(console): document all registered commands
anarchyysm Aug 19, 2026
a54dc23
docs(storage): fix partition layout and add USB MSC, VFS raw handoff …
anarchyysm Aug 19, 2026
1b28224
docs(ota): document C5 OTA over the SPI bridge and the build-time ver…
anarchyysm Aug 19, 2026
6f7830e
docs(sys_monitor): document heap, SD and I2C health checks and stall …
anarchyysm Aug 19, 2026
3d704ee
docs(st7789): fix init return type, resolution and rotation API
anarchyysm Aug 19, 2026
2fb34cf
docs(lvgl): document PSRAM draw buffers, direct-draw and capture APIs
anarchyysm Aug 19, 2026
c535e0e
docs(boot_report): document new boot stages and boot-count API
anarchyysm Aug 19, 2026
809ee82
docs(ui): update input-migration status and rewrite the add-a-screen …
anarchyysm Aug 19, 2026
7112d90
docs(sx1262): add driver doc covering shared SPI3 bus and RX hardening
anarchyysm Aug 19, 2026
76a2b71
docs(lora): add app doc for mesh session manager, Meshtastic and Mesh…
anarchyysm Aug 19, 2026
c9d706c
docs(subghz): fix spectrum task priority and note RX LED signalling
anarchyysm Aug 19, 2026
127e879
docs(gameboy): add Game Boy emulator and ROM picker documentation
anarchyysm Aug 19, 2026
e50b610
docs(nfc): add NFC app doc covering the stack and the simulation UI
anarchyysm Aug 19, 2026
05407be
docs(drivers): add docs for bq25896, led, i2c_init, pins, drv2605l, a…
anarchyysm Aug 19, 2026
7e20fb1
docs(services): add docs for power_manager, ir and sys_time
anarchyysm Aug 19, 2026
c3bbb3d
docs: fix index link, add new component rows and correct supported-ta…
anarchyysm Aug 19, 2026
a84e9b1
refactor(storage_api): remove dead tos_log SD tee and its stale stack…
anarchyysm Aug 19, 2026
94b12df
fix(cc1101): serialize spi3 transactions through the shared bus lock
lthiagovs Aug 20, 2026
4395e68
fix(subghz): transmit on gdo0 to match the async rx pin
lthiagovs Aug 20, 2026
8b6710b
fix(subghz): pace the analyzer sweep to release the spi bus
lthiagovs Aug 20, 2026
cb838fa
feat(subghz): store captures as real sub files on the sd card
lthiagovs Aug 20, 2026
df706b2
feat(subghz): publish decoded captures through a poll api
lthiagovs Aug 20, 2026
e96118f
feat(subghz): share rx preset and frequency across screens
lthiagovs Aug 20, 2026
0073f6a
feat(subghz): add a came brute force sweep
lthiagovs Aug 20, 2026
0f623fa
feat(subghz): replay saved captures over the air
lthiagovs Aug 20, 2026
2ae98d0
feat(ui): drive the subghz screens from the real radio
lthiagovs Aug 20, 2026
bcc47a0
feat(doom): port doomgeneric as an Applications component with HighBo…
anarchyysm Aug 20, 2026
d73669d
feat(ui): add DOOM entry to the games menu
anarchyysm Aug 20, 2026
489c838
build(partition): grow OTA slots to 2.875MB and shrink assets to 2.06…
anarchyysm Aug 20, 2026
b9e4606
fix(lvgl): complete LVGL flush in direct mode so the render task neve…
anarchyysm Aug 20, 2026
479c99a
docs: replace repo banner
anarchyysm Aug 20, 2026
e6caf12
chore(clang): clang formating source files
anarchyysm Aug 20, 2026
89e827b
chore(format): exclude vendored DOOM engine from clang-format and res…
anarchyysm Aug 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# ESP-IDF auto generated by build
sdkconfig
sdkconfig.old
dependencies.lock
**/dependencies.lock

# compiled output
/build/
Expand Down Expand Up @@ -1044,8 +1046,8 @@ size_info_*.txt
# pytest-embedded log folder
pytest_embedded_log/

# idf-component-manager output
dependencies.lock
# idf-component-manager lock: TRACKED for reproducible builds (pins the exact
# managed-component versions so every clone resolves the same deps).

!assets/
!assets/**
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ firmware_p4/ # ESP32-P4 master firmware (embeds C5 binary)
Drivers/ # Hardware drivers (SPI, buttons, display, radio, USB)
Service/ # Support services (OTA, WiFi, console, storage, SPI bridge)
Core/ # System core and main managers
Applications/ # User-facing apps (UI, bad_usb, SubGhz)
Applications/ # User-facing apps (UI, bad_usb, SubGhz, gameboy, nfc)
Drivers/spi_bridge_phy/ # SPI bridge physical layer (P4 side)
main/main.c # Entry point
common/metadata/ # Shared metadata
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<p align="center">
<img src="pics/Highboy_repo.png" alt="HighBoy Banner" width="1000"/>
<img src="pics/banner.png" alt="HighBoy Banner" width="1000"/>
</p>


Expand Down Expand Up @@ -45,7 +45,7 @@ See the general project architecture:

## How to use this project

We recommend that this project serves as a basis for custom projects with ESP32-S3.
We recommend that this project serves as a basis for custom projects with the ESP32-P4 and ESP32-C5.
To start a new project with ESP-IDF, follow the official guide:
[ESP-IDF Documentation - Create a new project](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html#start-a-new-project)

Expand Down
4 changes: 2 additions & 2 deletions README.pt.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<p align="center">
<img src="pics/Highboy_repo.png" alt="HighBoy Banner" width="1000"/>
<img src="pics/banner.png" alt="HighBoy Banner" width="1000"/>
</p>


Expand Down Expand Up @@ -47,7 +47,7 @@ Veja a arquitetura geral do projeto:

## Como utilizar este projeto

Recomendamos que este projeto sirva como base para projetos personalizados com ESP32-S3.
Recomendamos que este projeto sirva como base para projetos personalizados com o ESP32-P4 e o ESP32-C5.
Para começar um novo projeto com ESP-IDF, siga o guia oficial:
[Documentação ESP-IDF - Criar novo projeto](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html#start-a-new-project)

Expand Down
244 changes: 244 additions & 0 deletions docs/LoRa/README.md

Large diffs are not rendered by default.

17 changes: 16 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,33 @@ README.md, separated by `---`.

| Component | Docs |
|-----------|------|
| `audio_i2s` | [README.md](audio_i2s/README.md) - I2S audio output driver |
| `bad_usb` | [README.md](bad_usb/README.md) |
| `bluetooth` | [README.md](bluetooth/README.md) |
| `boot_report` | [README.md](boot_report/README.md) |
| `bq25896` | [README.md](bq25896/README.md) - TI BQ25896 battery charger / PMIC driver |
| `bridge_manager` | [README.md](bridge_manager/README.md) - P4<->C5 bridge lifecycle and coordination service |
| `buttons_gpio` | [README.md](buttons_gpio/README.md) |
| `c5_flasher` | [README.md](c5_flasher/README.md) |
| `cc1101` | [README.md](cc1101/README.md) |
| `console` | [README.md](console/README.md) |
| `dns_server` | [README.md](dns_server/README.md) |
| `drv2605l` | [README.md](drv2605l/README.md) - TI DRV2605L haptic motor driver |
| `esp_now` | [README.md](esp_now/README.md) |
| `espnow_chat` | [README.md](espnow_chat/README.md) |
| `gameboy` | [README.md](gameboy/README.md) - Game Boy emulator application |
| `host_link` | [app-guide.md](host_link/app-guide.md) [protocol.md](host_link/protocol.md) [README.md](host_link/README.md) |
| `http_server` | [README.md](http_server/README.md) |
| `i2c_init` | [README.md](i2c_init/README.md) - shared I2C bus initialization driver |
| `input_manager` | [README.md](input_manager/README.md) |
| `lvgl_port` | [README.md](lvgl_port/README.md) |
| `ir` | [README.md](ir/README.md) - infrared transmit/receive service |
| `led` | [README.md](led/README.md) - status/RGB LED driver |
| `LoRa` | [README.md](LoRa/README.md) - LoRa messaging application |
| `lvgl` | [README.md](lvgl/README.md) |
| `nfc` | [README.md](nfc/README.md) - NFC read/write application |
| `ota` | [README.md](ota/README.md) |
| `pins` | [README.md](pins/README.md) - board pin assignment definitions |
| `power_manager` | [README.md](power_manager/README.md) - battery and power-state management service |
| `recovery` | [README.md](recovery/README.md) |
| `sd_card` | [README.md](sd_card/README.md) |
| `spi` | [README.md](spi/README.md) |
Expand All @@ -38,8 +50,11 @@ README.md, separated by `---`.
| `storage_assets` | [README.md](storage_assets/README.md) |
| `storage_vfs` | [README.md](storage_vfs/README.md) |
| `SubGhz` | [README.md](SubGhz/README.md) |
| `sx1262` | [README.md](sx1262/README.md) - Semtech SX1262 LoRa radio transceiver driver |
| `sys_monitor` | [README.md](sys_monitor/README.md) |
| `sys_prio` | [README.md](sys_prio/README.md) |
| `sys_time` | [README.md](sys_time/README.md) - system clock / RTC time service |
| `tusb_desc` | [README.md](tusb_desc/README.md) |
| `ui` | [README.md](ui/README.md) [input-migration.md](ui/input-migration.md) |
| `wifi` | [README.md](wifi/README.md) |
| `ys_rfid2` | [README.md](ys_rfid2/README.md) - YS-RFID2 125 kHz RFID reader driver |
4 changes: 3 additions & 1 deletion docs/SubGhz/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ Captures RF signals via the CC1101 GDO0 pin routed to the ESP32 RMT RX periphera
4. **SCAN mode:** Protocol registry tries all decoders -> Analyzer for unknowns
5. **RAW mode:** Direct save to storage

**LED feedback:** The RX pipeline drives the status LED as it processes signals: `led_signal_info()` fires when a known protocol is decoded, and `led_signal_warning()` fires when RF is captured but no registered protocol matches.

#### API

```c
Expand Down Expand Up @@ -120,7 +122,7 @@ void subghz_spectrum_start(uint32_t center_freq, uint32_t span_hz);
void subghz_spectrum_stop(void);
bool subghz_spectrum_get_line(subghz_spectrum_line_t *out_line);
```
- Task stack: 4096 bytes, priority 1, Core 1.
- Task stack: 4096 bytes, Core 1. Priority comes from `sys_prio.h`: the `SYS_PRIO_BACKGROUND_LO` band (lowest non-idle background work), so the sweep never contends with the renderer or latency-sensitive services.
- Thread-safe reads via `subghz_spectrum_get_line`.

### Signal Analyzer (`subghz_analyzer`)
Expand Down
151 changes: 151 additions & 0 deletions docs/audio_i2s/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# Audio I2S Driver (P4)

This component drives the on-board audio path of the HighBoy V2 (ESP32-P4 firmware only): a class-D speaker amplifier for playback (TX) and a PDM microphone for capture (RX), both on a single I2S port. It owns one persistent TX channel used for UI chimes, tones, melodies, raw PCM and continuous streaming, and opens independent PDM-RX channels for mic recording and live streaming.

## Overview

- **Location:** `firmware_p4/components/Drivers/audio_i2s/`
- **Header:** `include/audio_i2s.h`
- **Firmware:** `firmware_p4` only (no C5 counterpart)
- **Dependencies:** `driver/i2s_std`, `driver/i2s_pdm`, `driver/gpio`, `freertos`, `pin_def`, `sys_prio`
- **I2S port:** `I2S_NUM_0` (master role). The single TX channel and the PDM-RX channels share this one port.

> **Part naming note:** the public header docstrings refer to a **MAX98357A** amplifier, while the driver source (`audio_i2s.c`) and the pin map (`pin_def.h`) name an **NS4168** amp and an **MSM261** PDM mic. The code and pin comments are the authoritative wiring reference; the amplifier is enabled by taking its shutdown pin high, and its hardware gain is fixed, so volume is applied digitally.

## Signal Path

### TX (speaker / amplifier)

- **Mode:** I2S standard (Philips) slot format, **16-bit**, **mono**, master.
- **Default sample rate:** `44100` Hz (`SAMPLE_RATE_HZ`). PCM and stream calls may pass any rate; the driver reconfigures the TX clock only when the requested rate actually changes.
- **One persistent channel:** `I2S_NUM_0` has exactly one TX channel. It is created once at init and never deleted; playback only enables/disables it and reconfigures its clock. Creating/deleting a channel per sound churned internal DMA RAM and stuttered the UI, so that is avoided.
- **DMA depth:** `AUDIO_DMA_DESC_NUM` = 8 descriptors x `AUDIO_DMA_FRAME_NUM` = 256 frames (~46 ms, ~8 KB internal RAM), deeper than the IDF default for underrun slack.
- **Underrun behaviour:** `auto_clear = true`, so a starved channel emits zeros instead of looping the stale buffer.
- **Anti-click:** each note gets a raised-cosine attack (`ENV_ATTACK_MS` = 4 ms) / release (`ENV_RELEASE_MS` = 8 ms) envelope, and playback brackets sounds with short silence; melodies use a continuous phase accumulator for gapless rendering.
- **Amp enable:** `GPIO_AUDIO_EN_PIN` is driven high (out of shutdown) at init; idempotent.

### RX (PDM microphone)

- **Mode:** PDM RX, **16-bit**, **mono**, master.
- **Filtering:** high-pass filter enabled with a 50 Hz cut-off (`hp_cut_off_freq_hz`), digital gain `amplify_num = 3`. A ~120 ms settle delay is applied after enable to let the HP filter converge.
- **Channels:** the mic uses its own RX channel on `I2S_NUM_0`, independent of the TX side. `audio_i2s_mic_record()` opens/closes a channel per call; the streaming API keeps a persistent RX channel (`s_rx_stream`).

## Concurrency

- Playback runs on a pinned task `"audio_i2s"`: stack `AUDIO_TASK_STACK_SIZE` = 4096, priority `SYS_PRIO_SERVICE_LO`, core `SYS_CORE_RADIO`. It is deliberately **not** on the UI core, because the LVGL renderer at `SYS_PRIO_RENDER` would starve the I2S DMA during a full-frame redraw.
- A single mutex (`s_tx_mux`) guards the shared TX channel. Callers from the LVGL thread use finite timeouts and drop the sound rather than stall the UI:
- `TX_LOCK_WAIT_MS` = 250 ms for blocking playback / stream claims.
- `FX_TX_WAIT_MS` = 0 for queued UI effects (never wait behind a melody).
- Queued UI effects (`audio_play_chime`, `audio_click`) post `fx_t` entries to a depth-4 queue (`QUEUE_DEPTH`); overflow is dropped so button mashing never piles up.
- While a TX stream is active (`s_streaming`), one-shot playback calls become no-ops so they do not fight the stream.

## Pins (from `pin_def.h`)

| Signal | Define | GPIO |
| :--- | :--- | :--- |
| Amp enable / shutdown | `GPIO_AUDIO_EN_PIN` | 49 |
| I2S bit clock (BCLK) | `GPIO_AUDIO_BCLK_PIN` | 28 |
| I2S word select (LRCLK / WS) | `GPIO_AUDIO_LRCLK_PIN` | 29 |
| I2S data out (DOUT) | `GPIO_AUDIO_DIN_PIN` | 27 |
| Mic PDM clock | `GPIO_MIC_PDM_CLK_PIN` | 54 |
| Mic PDM data | `GPIO_MIC_PDM_DATA_PIN` | 53 |

MCLK and the TX-side DIN are `I2S_GPIO_UNUSED`.

## API Reference

### Initialization

#### `audio_i2s_init`
```c
esp_err_t audio_i2s_init(void);
```
Brings up `I2S_NUM_0` on the amp pins, allocates the DMA chunk buffer, mutex and effect queue, and starts the playback task. Idempotent; safe to call multiple times.

#### `audio_i2s_set_volume`
```c
void audio_i2s_set_volume(uint8_t pct);
```
Sets global output volume (0..100), clamped. Applied as a perceptual (square-law) digital scale on top of each sound's own amplitude, because the amplifier's hardware gain is fixed.

### Tones and Melodies

#### `audio_i2s_play_tone`
```c
esp_err_t audio_i2s_play_tone(float freq_hz, int dur_ms, float amp);
```
Plays a single blocking sine tone at 44.1 kHz mono. `amp` is in [0..1]. Returns `ESP_ERR_TIMEOUT` if the channel is busy (sound dropped), `ESP_OK` otherwise (also when not ready or a stream is active).

#### `audio_i2s_play_song` / `audio_i2s_play_song_cb`
```c
esp_err_t audio_i2s_play_song(const audio_note_t *notes, int count, float amp);
esp_err_t audio_i2s_play_song_cb(const audio_note_t *notes, int count, float amp,
audio_song_progress_cb_t cb, void *ctx);
```
Plays a melody blocking and gapless: opens the channel once, renders all notes back-to-back with per-note anti-click envelopes and a continuous phase accumulator, then ends. The `_cb` variant invokes `cb` before each note (in the worker thread) with the note index, total count and frequency; returning `false` cancels playback cooperatively after the current note. Pass `cb = NULL` for plain playback.

`audio_note_t` is `{ uint16_t freq_hz; uint16_t dur_ms; }`; `freq_hz == 0` is a rest (silence).

`audio_song_progress_cb_t`:
```c
typedef bool (*audio_song_progress_cb_t)(int note_index, int note_count,
uint16_t freq_hz, void *ctx);
```
Must be trivial (touch only volatile scalars); never call `lv_*` from it.

### Raw PCM Playback

#### `audio_i2s_play_pcm`
```c
esp_err_t audio_i2s_play_pcm(const int16_t *pcm, size_t n_samples, uint32_t sample_rate);
```
Plays a raw 16-bit mono PCM buffer (blocking) at `sample_rate`. Reconfigures the TX clock to the given rate and appends a short tail-silence.

### Continuous TX Streaming

#### `audio_i2s_stream_start` / `audio_i2s_stream_write` / `audio_i2s_stream_stop`
```c
esp_err_t audio_i2s_stream_start(uint32_t sample_rate);
int audio_i2s_stream_write(const int16_t *pcm, int n_samples);
void audio_i2s_stream_stop(void);
```
Begins a continuous 16-bit mono TX stream (e.g. WAV playback), reusing the shared TX channel and suppressing UI chimes/clicks for its duration. `stream_write` applies global volume, blocks and paces to real time via the I2S DMA, and returns samples written (or -1 if the stream is not active). `stream_stop` drains the DMA, restores the default clock and re-enables UI sounds; safe when not started.

### PDM Microphone Capture

#### `audio_i2s_mic_record`
```c
esp_err_t audio_i2s_mic_record(int16_t *out, size_t max_samples, uint32_t sample_rate,
size_t *out_captured, audio_mic_level_cb_t cb, void *ctx);
```
Captures up to `max_samples` of 16-bit mono PCM from the PDM mic (blocking): opens a PDM-RX channel, lets the HP filter settle (~120 ms), fills `out`, then closes. `*out_captured` receives the real sample count. If `cb` is non-NULL it is invoked after each chunk with that chunk's peak and RMS level for a live VU meter.

`audio_mic_level_cb_t`:
```c
typedef void (*audio_mic_level_cb_t)(int peak, int rms, void *ctx);
```
`peak` is max |sample| (0..32767) of the last chunk. Runs in the recording task's context; keep it trivial.

#### `audio_i2s_mic_stream_start` / `audio_i2s_mic_stream_read` / `audio_i2s_mic_stream_stop`
```c
esp_err_t audio_i2s_mic_stream_start(uint32_t sample_rate);
int audio_i2s_mic_stream_read(int16_t *buf, int max_samples);
void audio_i2s_mic_stream_stop(void);
```
Opens a persistent PDM-RX stream at `sample_rate` (idempotent). `mic_stream_read` reads up to `max_samples` 16-bit mono samples, returning the count read (0 on error/timeout/not-started). `mic_stream_stop` stops and frees the RX channel; safe when not started.

### UI Sound Effects

#### `audio_play_chime`
```c
void audio_play_chime(void);
```
Queues a 3-note boot chime (C5 -> E5 -> G5, ~130-180 ms each). Non-blocking; dropped if the queue is full.

#### `audio_click`
```c
void audio_click(void);
```
Queues a short click (~30 ms, ~2 kHz). Non-blocking; dropped if the queue already holds pending entries so rapid button presses never pile up.
</content>
</invoke>
Loading
Loading