# Phase 4: HID Data Pipeline - Context

**Gathered:** 2026-03-22
**Status:** Ready for planning

<domain>
## Phase Boundary

Driver reliably reads raw proximity data and calibration parameters from the Beyond 2 over USB HID. This phase builds the data pipeline from HID device to cached values in the driver — no proximity algorithm or SteamVR integration (those are Phases 5 and 6). Includes report reading, calibration parameter extraction, report rate configuration, and USB disconnect/reconnect handling.

</domain>

<decisions>
## Implementation Decisions

### HID reading model
- Background reader thread inside HidDevice class (extends existing RAII wrapper)
- HidDevice gains StartReading()/StopReading() methods that manage an internal thread
- Thread calls hid_read() in a loop with 500ms timeout
- Thread writes latest prox_distance to an atomic uint16 — RunFrame reads cached value (lock-free)
- Only latest value matters for proximity; no queue needed at this phase
- hid_open() called once on connect (or reconnect) — device stays open for driver's entire lifetime

### Report rate configuration
- Default report rate: 500ms (2 reports/sec)
- Rate command ('R' + uint16 big-endian milliseconds) sent immediately after successful hid_open, before starting reader thread
- Rate is sent via HID feature report (same pattern as Python: `send_feature_report(bytes([0, 'R', msb, lsb]))`)

### Disconnect/reconnect handling
- Reader thread detects disconnect when hid_read() returns -1
- On disconnect: close device, enter reconnect loop within the reader thread (self-contained)
- Retry hid_open every 5 seconds (periodic, not exponential backoff)
- On successful reconnect: re-read calibration parameters, re-send rate command, resume reading
- DeviceProvider just sees data stop/start — no awareness of reconnect internals
- Pipe 'status' command exposes connection state: `hid=open/closed/reconnecting`

### Calibration read flow
- Full 512-byte user signature page read via 16 sequential READ_SIG feature reports (32 bytes each)
- TLV parsing with CRC8 validation (polynomial 0x07, init 0xFF) — reject entries with bad CRC
- Extract 4 tags: programmed_cal (0x06), proximity_threshold (0x0B), proximity_hysteresis (0x0C), user_trim (0x0E)
- Missing tag defaults: programmed_cal=0, threshold=firmware default, hysteresis=firmware default, user_trim=0
- Log which tags were found and which fell back to defaults
- Calibration values exposed in pipe 'status' response: `proximity=X hid=Y cal=Z thresh=T hyst=H trim=U`
- Calibration read performed on initial connect AND on every reconnect (user may have recalibrated)

### Claude's Discretion
- Thread synchronization primitives (std::atomic vs mutex for cached values)
- HID feature report send/receive helper method signatures
- User signature TLV parser implementation details (inline vs separate class)
- Exact log message formatting and verbosity levels
- Whether to add a new `src/hid/user_signature.h` or keep TLV parsing inside HidDevice

</decisions>

<canonical_refs>
## Canonical References

**Downstream agents MUST read these before planning or implementing.**

### HID protocol (periodic reports)
- `code_samples/proximity_sensor_access/prox_config.py` lines 226-259 — Periodic data packet format: header '#', byte 1=length, bytes 4-5=prox_distance (uint16 big-endian). Also shows rate command: `bytes([0, ord('R')]) + struct.pack('>H', rate_ms)`
- `code_samples/proximity_sensor_access/prox_monitor.py` lines 18-44 — HID reader thread pattern, report rate adjustment via feature report

### Calibration / user signature flash
- `code_samples/proximity_sensor_access/config_lib.py` — Full TLV format documentation, SigTag enum (0x06=Prox_Cal, 0x0B=Threshold, 0x0C=Hysteresis, 0x0E=User_Prox_Trim), CRC8 implementation, read_sig() 16-chunk feature report sequence, parse_sig() TLV parser
- `code_samples/beyond_firmware/src/Devices/prox_control.c` lines 22-77 — Firmware init showing how calibration params are loaded from signature tags with defaults
- `code_samples/beyond_firmware/src/Devices/prox_control.h` — MIN_PROX_VALUE (100), MAX_PROX_VALUE (16383), Proximity_T struct with all calibration fields

### Existing driver code
- `src/hid/hid_device.h` — Current RAII wrapper (Open/Close/IsOpen) — needs reader thread, feature report, and read methods added
- `src/hid/hid_device.cpp` — Current implementation to extend
- `src/driver/device_provider.cpp` — DeviceProvider::Init() does hid_open, RunFrame polls pipe. Will consume cached HID data.
- `src/driver/device_provider.h` — DeviceProvider class with m_pHidDevice, m_bProximity, pipe infrastructure

### Project requirements
- `.planning/REQUIREMENTS.md` — HID-02, HID-03, HID-04, HID-05 define Phase 4 requirements

</canonical_refs>

<code_context>
## Existing Code Insights

### Reusable Assets
- `HidDevice` class (`src/hid/hid_device.h`) — RAII wrapper with Open/Close/IsOpen. Extend with read/write/feature report methods and background thread.
- `DeviceProvider::RunFrame()` — Currently only polls pipe. Will also read cached HID values after this phase.
- `DeviceProvider::HandlePipeCommand()` — Pipe command handler. Extend 'status' response with connection state and calibration values.
- `beyond_prox_ctl` CLI tool (`src/ctl/main.cpp`) — Already sends commands and displays responses. No changes needed.

### Established Patterns
- RAII wrappers for external resources (HidDevice)
- CMake build with vendored HIDAPI (extern/hidapi/)
- DriverLog for all driver-side logging
- Atomic PowerShell verification scripts with numbered checks
- Named pipe debug channel with command-response protocol

### Integration Points
- `HidDevice` — Primary extension point: add thread, read, feature report, and calibration read methods
- `DeviceProvider::Init()` — After hid_open, trigger calibration read and start reader thread
- `DeviceProvider::RunFrame()` — Read cached prox_distance from HidDevice (Phase 5 will use this value)
- `DeviceProvider::HandlePipeCommand("status")` — Extend response format
- `CMakeLists.txt` — May need threading library link (std::thread is header-only on MSVC, likely no changes)

</code_context>

<specifics>
## Specific Ideas

- hid_open only on first connect or reconnect — device stays open for entire driver runtime to minimize CPU overhead and report sluggishness
- 500ms report rate chosen deliberately: conservative on USB traffic, 8 seconds to fill 16-sample moving average (acceptable for headset on/off detection)
- 500ms hid_read timeout: low CPU, adequate responsiveness for checking thread shutdown flag
- Reader thread is self-contained: detects disconnect, handles reconnect loop, re-reads calibration — DeviceProvider doesn't need to manage reconnection state

</specifics>

<deferred>
## Deferred Ideas

None — discussion stayed within phase scope

</deferred>

---

*Phase: 04-hid-data-pipeline*
*Context gathered: 2026-03-22*
