#pragma once #include #include // Phase 14 locks v3.0 LED count at 10. Kept as a controller-level const; transport // is indifferent to the count. // // NOTE (from 14.1 spike findings): The MagWLED-1 hardware physically has 12 LEDs // (10 visible + 2 spares). This constant governs the LedController surface only — // the transport's SendRgbFrame accepts arbitrary numLeds and encodes the Adalight // count field as N-1. Plan 14-03 owns the runtime resolution of the real strip // length; this plan's LedController is locked to 10 per the v3.0 spec. static constexpr int kBackglowMaxLeds = 10; // Abstract transport. Any concrete impl must be non-blocking from the caller's // perspective — blocking serial/network I/O is acceptable *inside* the transport // because the LedController writer thread is the only caller and is never on // the SteamVR main thread. class ILedTransport { public: virtual ~ILedTransport() = default; // Open/close the transport. portName is transport-specific (COM port for // serial, host:port for future DDP). Returns true on success. virtual bool Open(const std::string& portName) = 0; virtual void Close() = 0; virtual bool IsOpen() const = 0; // Send one LED frame. rgb points to numLeds*3 bytes in R,G,B order // (channel order matched to WLED expectation — default RGB; if spike // findings indicate GRB, adjustment happens at the transport impl, not here). // Returns true on successful write. On failure, implementations MUST // internally invalidate the handle so the next Open() can be attempted by // the owning LedController. virtual bool SendRgbFrame(const uint8_t* rgb, int numLeds) = 0; // Non-streaming control — short JSON lines over the same transport. virtual bool SendBrightness(uint8_t value) = 0; virtual bool SendPower(bool on) = 0; // Last-error accessor for logging. Returns a Win32 error code for serial; // may return 0 if Open has never failed. virtual unsigned long LastErrorCode() const = 0; };