--- name: tactility-firmware-development description: Use when merging current Tactility firmware, preserving local ES3C28P/ES3C35P customizations, building/flashing ESP32 firmware, or validating external apps against it. --- # Tactility firmware development ## Scope and success criteria Use this skill for firmware upgrades, especially when upstream changes the app loader, dashboard API, SDK export, or device model. Before editing, record the active branch, `git status --short`, selected `Devices/`, serial port, and the expected device identity. Preserve user work and local board customizations; do not reset or overwrite a dirty tree. Success is not merely a successful flash: the board must boot, mount storage, return `/api/sysinfo`, expose required internal apps, and accept an external app rebuilt against this exact firmware. ## Upgrade and customization audit 1. Fetch and compare the intended upstream branch before merging. Treat `upstream/main` as distinct from experimental release/IDF branches unless the task explicitly asks for one of those branches. 2. Merge without discarding local work (for example, `git merge --autostash upstream/main` after inspecting status). Resolve conflicts by preserving required ES3C28P and ES3C35P device definitions, partition selection, display/font customizations, and product features. 3. Compare the pre-upgrade customization commit against the resulting worktree. Check new app registrations, CMake/source inclusion, settings pages, web-server endpoints, and board-specific `sdkconfig` entries—not just files that happen to conflict. 4. Commit the resulting firmware customization as a focused, reviewable commit after `git diff --check`. ## Multi-binary external-app compatibility Upstream app packaging changed to `bin//.elf`. The old `elf/.elf` archive layout produces a loader `Not executable` error. - Manifest v0.2: `bin/esp32s3/app.elf` - Manifest v0.3: `bin/esp32s3/.elf` When this change arrives, update the companion app tool and rebuild every app from a fresh SDK exported from this firmware. Do not attempt to repair a packaged ELF on the SD card: its layout and ABI must both be regenerated. ## Build and flash Use the installed IDF 5.5 environment; host virtual environments can corrupt both Python dependencies and IDF tooling: ```zsh unset VIRTUAL_ENV PYTHONPATH PYTHONHOME export IDF_PYTHON_ENV_PATH=/Users/adolforeyna/.espressif/python_env/idf5.5_py3.9_env source /Users/adolforeyna/esp/esp-idf/export.sh # Select/check the intended board before this step. python device.py idf.py build idf.py -p /dev/cu.usbmodemXXXX flash ``` `Tactility/CMakeLists.txt` uses a non-configure-dependent source glob. After adding a new `.c`/`.cpp` file, run `idf.py reconfigure build`; otherwise a linker error for a newly referenced symbol may only mean CMake has not discovered the source file yet. ## Boot and feature acceptance Capture serial at 115200 after flash or reset. Confirm the board name, SD-card mount, HTTP-server start, Wi-Fi address, and any feature-specific startup logs. Then query the resolved device: ```zsh curl -fsS http:///api/sysinfo curl -fsS http:///api/apps ``` For MCP settings, verify the `McpSettings` internal app appears in `/api/apps`. When enabled, verify MCP stream startup logs. For a feature restored from an older customization, validate its registration path and persisted settings, not only its source files. ## External-app acceptance gate Use the companion app skill's exact-firmware wrapper: ```zsh cd /path/to/tactility_apps scripts/build_current_firmware_app.sh Apps/MyApp --firmware /path/to/tactility ``` Inspect the resulting tar member path, install through port-80 dashboard API, launch it, and read serial. Required evidence is the loader's `Loading .../bin/...`, an ELF entry address, `Task started`, and app-specific startup logs. HTTP 200 or a package simply appearing in `/api/apps` is insufficient.