================================================================
 PoseLab Core (pio) - PlatformIO Build Guide
================================================================

Updated : 2026-08-31

Target board : ESP32-S3-WROOM-1 N16R8 (16MB flash, 8MB OPI PSRAM)
USB-UART     : CH343P (CDC, driverless) - enumerates as a COM port
Transport    : UART0 @ 2,000,000 baud, 50fps, 96-byte AnalyzedFrame packet
               (86 bytes + a 10-byte on-device inference block)

----------------------------------------------------------------
 1. Prerequisites
----------------------------------------------------------------
- VS Code + the PlatformIO IDE extension
  (or the CLI on its own: pip install platformio)
- The platform and libraries are declared in platformio.ini and are downloaded
  automatically on the first build. No manual installation is needed.
    platform : espressif32 6.11.0  (arduino-esp32 2.0.17)
    lib_deps : Chirale_TensorFLowLite 2.0.0  <- on-device inference (TFLite Micro)
               Adafruit NeoPixel     ^1.12.0
               ArduinoJson           ^7.1.0  <- must be v7, NOT v6

----------------------------------------------------------------
 2. Opening the project
----------------------------------------------------------------
- Open this folder (PoseLabCore-pio/) as a PlatformIO project.
  The folder containing platformio.ini is the project root.
- The sources live in a tree under src/
  (board/ sense/ calib/ proto/ tinyml/ model/ ...).
- The entry point is src/main.cpp.

----------------------------------------------------------------
 3. Build / upload / monitor
----------------------------------------------------------------
    pio run                 build (env:n16r8 - the only env)
    pio run -t upload       upload
    pio run -t monitor      serial monitor (2,000,000 baud)

- The port is pinned to COM7 in platformio.ini.
  For a different port, either edit upload_port / monitor_port or override it
  on the command line:
    pio run -t upload --upload-port COM12

----------------------------------------------------------------
 4. Key platformio.ini settings (* do not change these)
----------------------------------------------------------------
  board                        : esp32-s3-devkitc-1
  build_flags
    -DARDUINO_USB_CDC_ON_BOOT=0  <- important. Serial = UART0 (CH343P bridge).
                                    If set to 1, no data comes out
    -I src                       <- resolves subfolder includes like "board/pins.h"
    -DBOARD_HAS_PSRAM            <- declares PSRAM usage
  board_build.partitions       : partitions-16mb.csv
                                 <- * custom partition table containing the fit
                                    NVS partition and the models SPIFFS
                                    partition. With the default table,
                                    calibration values and uploaded models are
                                    not persisted
  board_build.flash_size       : 16MB
  board_build.arduino.memory_type : qio_opi   <- enables the 8MB OPI PSRAM
  upload_speed                 : 921600
  monitor_speed                : 2000000

  NOTE: The MUX EN pins never use GPIO35-37 (reserved for PSRAM), so enabling
        PSRAM causes no conflict.
        The pin assignment lives in src/board/pins.h.

  NOTE: PSRAM is not optional here. An uploaded model is staged in PSRAM in one
        piece before it is written to SPIFFS, so a board without working PSRAM
        cannot accept a model upload.

----------------------------------------------------------------
 5. Upload & verify
----------------------------------------------------------------
- Connect at 2,000,000 baud with pio run -t monitor.
- Example boot banner:
    ==== PoseLab Core ====
    Chip       : ESP32-S3 ... Flash 16MB, PSRAM 8189KB   <- PSRAM detected
    FIT calib loaded: USER params                        <- calibration persisted
    PUMP- ENTER ...                                      <- streaming started
- On boot the WS2812C LED runs a rainbow sequence, then holds amber = normal.
- If a model has been uploaded, the banner also reports the model it loaded and
  a selftest line. With no model, inference is simply off (appId = 0x00 in the
  packet) and everything else works normally.

----------------------------------------------------------------
 6. Serial commands
----------------------------------------------------------------
  STOP / RESTART           pause / resume the 50fps stream
  FITWR / FITRD / FITCLR   per-channel calibration in the "fit" NVS partition
  MDLWR / MDLRD / MDLCLR   upload / read back / erase the .plmodel in SPIFFS

- MDLWR turns streaming off by itself for the duration of the transfer and
  turns it back on when the transfer ends, including on error or timeout.
- The device does not reboot on upload. A newly uploaded model takes effect at
  the next boot, because the interpreter is built once at startup.
- The browser sends models for you: the MLP lab page has an On-Device panel.
  See the SDK protocol document for the raw framing if you are writing your own
  tool.

----------------------------------------------------------------
 7. Notes
----------------------------------------------------------------
- To build with the Arduino IDE instead, use the PoseLabCore-adv package
  (its entry point is a .ino and its includes carry the "src/..." prefix).
  Runtime behaviour is identical - adv is generated from this source.
- The 86-byte protocol is retired. This firmware emits 96 bytes only.
- Support: support@poselab.app
