The Feasycom BT1035 programming user guide's own pin table (§2.2, pin
34 SYS_CTRL) reads "Delay 100ms, pull high" -- the previous reset
sequence here asserted SYS_CTRL high at the very same instant as
RESET, with zero lead-in delay, racing the module's own documented
power-on requirement (the datasheet's §4.7 separately confirms
SYS_CTRL must be asserted >20ms before internal regulators even start
powering up). Rewrote resetAndInitOnce() to hold both pins low for a
100ms lead-in matching the guide exactly, then bring SYS_CTRL high,
then an extra 50ms settle margin before releasing RESET into a module
that's had a chance to actually power up first.
This is verified correct against the manufacturer's own documented
timing and is worth keeping regardless of its effect on any one
symptom, but it does NOT fully explain this project's intermittent
BT1035 boot failures ("no spontaneous UART bytes after hardware
reset"): a deep investigation session confirmed the same failure
still occurs, at the same rate, across genuine physical power cycles
(not just soft resets) with this fix applied, extended UART listen
windows (tested up to 10s vs the normal 3.5s), and independently
schematic-verified-correct GPIO pin assignments, UART TX/RX wiring,
AT command bytes, and shared 3.3V regulator sizing. Unlike the
Si4684 ARG1-offset bug earlier this session -- which failed 100% of
the time, deterministically, from a real code defect -- this failure
is non-deterministic across identical power-on sequences with
identical code, which does not match a firmware logic-bug signature.
Root cause remains open; see docs/si4684-rf-investigation-report.md.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0178rASQ6ZETPMUamvpoR2KR
BT1035Driver::boot() had zero retry on the reset+AT-init sequence — a
single hardware RESET# pulse followed immediately by AT commands,
with no second attempt if the module didn't come up in time. This is
the most plausible explanation for the intermittent "no spontaneous
UART bytes after hardware reset" / "AT init failed" boot failures
logged in docs/si4684-rf-investigation-report.md and observed again
live this morning on otherwise-identical hardware/wiring — classic
power-up timing jitter, not a permanent fault. Extracted the reset+
init sequence into resetAndInitOnce() and wrapped it in a 3-attempt
retry loop with a short delay between attempts; the one-time GPIO
config and UART driver install stay outside the loop since they don't
need repeating. Root cause of the underlying jitter is still open.
BluetoothJson.hpp was the only *Json.hpp module in the core with zero
host test coverage (status/scan/paired serialisation, auto-reconnect/
connect/speaker parsing) — every sibling module already has one.
Added bluetooth_json_test.cpp following the existing tuner_json_test
pattern; ctest now covers 20 suites instead of 19.
Documentation catch-up, found doing a full firmware re-review at the
user's request:
- POST /api/tuner/calibrate-antenna and the antcap field on
POST /api/tuner/tune (added in a previous commit, never documented)
are now in ch-api.tex.
- kFirmwareVersion was still hardcoded "0.8.5" despite the RF fixes,
BLE provisioning, phone streaming, antenna calibration, and generic
DSP param API landed since that version's actual release commit
(0a1188a). Bumped to 0.9.0 everywhere it's mentioned (health JSON,
the manual's title page, intro, classes, and API chapters).
- instructions.md and docs/TODO.md still described the firmware as
frozen at 0.8.5 awaiting hardware-in-the-loop testing that has since
happened extensively; docs/TODO.md's H5 verdict specifically still
said "suspect U6 RF ground (re-open PCBWay)" for a bug that turned
out to be firmware, not hardware — actively misleading, corrected.
Both files now summarise the post-0.8.5 HIL findings and current
open items (BT1035 root cause, intermittent HTTP unresponsiveness
under load, antenna-limited signal quality, possibly-undersized 24 KB
nvs partition).
Verified: idf.py build, doxygen (0 warnings), check-manual-sync,
check_si4684_blobs, ctest (20/20), two-pass xelatex manual build all
green. Flashed and confirmed live: fw reports 0.9.0, BT1035 booted on
the first attempt post-flash.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0178rASQ6ZETPMUamvpoR2KR
Redundant AT+RESET sent right after the hardware RESET# pulse could interrupt
the module mid bring-up; boot-banner probe window (1500ms) was too short for
the real +VER banner (~5s), causing spurious "AT init failed". 5/5 clean
boots after fix vs ~1/13 before.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Streaming (main feature this session):
- New WebRadioConfig/WebRadioJson core types, ISecureStore-backed persistence
- New webradio::WebRadioService (thread-safe live config) + GET/POST /api/streaming
- web_radio_stream task now runtime-toggleable (no reboot), no hardcoded URL
- Content-Type diagnostic: warns clearly when a URL is a webpage, not an audio stream
Boot cleanup:
- Removed boot-time auto FM/DAB tune, auto-beep, and the (now-concluded) Si4684
crystal IBIAS/CTUN empirical sweep from main.cpp — tuning/beep are on-demand
via the existing REST API only
Web UI:
- Modernized styling (cards, gradients, toggle switches, light/dark theme)
- New Stream tab wired to /api/streaming
Fixes found via real idf.py build (not just clangd):
- Restored wrongly-removed si4684/Si4684Tuner.hpp include in main.cpp
- Fixed MP3Decode() argument types in web_radio_stream.cpp (unsigned char**/int*)
Quality-gate fixes:
- Host-test stub headers (esp_log.h, freertos/*) so TunerService.cpp's
scanForStation logging/pacing compiles for station_service_test /
integration_service_test instead of running stale binaries
- Added WifiScanner and WebRadioService manual sections; filled in missing
Doxygen docs on BluetoothService, i2s_sdata_probe, test_firmware, Bt1035At
- Ignore clangd's .cache/ index directory
Also includes prior uncommitted work carried in the tree: Wi-Fi/Bluetooth
device scan REST API and UI (WifiScanner, BT scan), SigmaStudio TCP bridge,
and the current ADAU1701 SigmaStudio DSP program export.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Switch BT1035 bring-up from Line-In to I2S slave (AT+AUXCFG=3, AT+I2SCFG=67) to match the ADAU1701 PCM routing, confirm 2 kΩ I2C pull-ups on R1/R16, and sync firmware docs, AGENTS rules, and the DATASHEET bundle.
Co-authored-by: Cursor <cursoragent@cursor.com>
Align README, manual, and backlog to 0.8.4; add Web UI System tab for OTA/DSP uploads, serial in health header, FM seek down, and BT1035 paired list plus auto-reconnect API.
Co-authored-by: Cursor <cursoragent@cursor.com>
Read the factory 24AA025E48 serial after ADAU I2C boot, derive SoftAP SSID, BT name, STA hostname, and expose serialNumber on GET /api/health with graceful fallbacks.
Co-authored-by: Cursor <cursoragent@cursor.com>
Clear doc-block warnings so doxygen exits 0, add GitHub Actions
for host tests, Doxygen, and manual sync, and document CI in the manual.
Co-authored-by: Cursor <cursoragent@cursor.com>
Expose discoverable mode and A2DP control over REST, add persisted
DAB/FM preset list with web UI, and document gaps in docs/TODO.md.
Co-authored-by: Cursor <cursoragent@cursor.com>
Implement Bt1035Driver AT init (AT+AUXCFG=1), core AT parser with host tests,
wire boot into HardwareBootstrap, and document DAB/FM tuning workflows in ch-si4684.
Co-authored-by: Cursor <cursoragent@cursor.com>
Implement ESP-IDF walking skeleton with SoftAP, health API, and host
tests, then Slice 2 ISecureStore/NvsSecureStore, STA join, POST
/api/wifi, and the provisioning web UI.
Co-authored-by: Cursor <cursoragent@cursor.com>