Skip to content

File SimGateway.h

File List > Firmware > Libraries > SimGateway > SimGateway.h

Go to the documentation of this file


#pragma once
#ifdef ARDUINO_ARCH_RP2040

#include <Arduino.h>
#include <HIDControls.h>

#include "AxisCal.h"

namespace OpenSkyhawk {

class HIDAxis {
public:
    HIDAxis(uint16_t controlId, uint8_t axisIndex);

    static HIDAxis* head();       
    uint16_t controlId() const;   
    uint8_t  axisIndex() const;   
    void     dispatch(uint16_t value);
    HIDAxis* next() const;        

private:
    static HIDAxis* _head;
    HIDAxis*        _next;
    uint16_t        _controlId;
    uint8_t         _axisIndex;
};

class HIDButton {
public:
    HIDButton(uint16_t controlId, uint8_t buttonIndex);

    static HIDButton* head();
    uint16_t controlId() const;
    void      dispatch(uint16_t value);
    HIDButton* next() const;

private:
    static HIDButton* _head;
    HIDButton*        _next;
    uint16_t          _controlId;
    uint8_t           _buttonIndex;
};

class HIDHatSwitch {
public:
    HIDHatSwitch(uint16_t controlId, uint8_t hatIndex);

    static HIDHatSwitch* head();
    uint16_t controlId() const;
    void          dispatch(uint16_t value);
    HIDHatSwitch* next() const;

private:
    static HIDHatSwitch* _head;
    HIDHatSwitch*        _next;
    uint16_t             _controlId;
    uint8_t              _hatIndex;
};

} // namespace OpenSkyhawk

namespace SimGateway {

static constexpr uint8_t DEFAULT_UART_TX_PIN = 0; 
static constexpr uint8_t DEFAULT_UART_RX_PIN = 1; 

// Firmware version reported in the calibration protocol's HELLO_ACK, so the client can show
// which build a device is running. Keep in step with library.json.
#define SIMGATEWAY_FW_MAJOR 0
#define SIMGATEWAY_FW_MINOR 1
#define SIMGATEWAY_FW_PATCH 0

void setup(SerialUART& uart,
           uint8_t txPin = DEFAULT_UART_TX_PIN,
           uint8_t rxPin = DEFAULT_UART_RX_PIN);

void loop();

const OpenSkyhawk::CalBlob& calibration();

// ── Status LEDs (Gateway_Bridge board) ────────────────────────────────────────
//
// Two board-mounted status LEDs report the gateway's USB / data / fault state at a
// glance: RED = GP3, GREEN = GP2, board-mounted 0805, active-high (HIGH = on). The
// animator is non-blocking (millis(), never delay()) and is ticked from loop(), so
// sketches need no LED code. The RP2040 module's onboard WS2812 is not used.
// See docs/architecture/sim-gateway.md for the user-facing table.

enum class LedState : uint8_t {
    FAULT,     
    NO_HOST,   
    STREAMING, 
    USB_IDLE,  
    INIT,      
};

enum class Anim : uint8_t {
    OFF,   
    SOLID, 
    SLOW,  
    FAST,  
    ALT,   
    PULSE, 
};

void statusLedBegin();

void statusTick();

#ifdef SIMGATEWAY_TEST
bool feedByte(uint8_t b);

void resetParser();

void resetCdcCapture();

size_t cdcCaptureCount();

uint8_t cdcCaptureByte(size_t index);

bool cdcCaptureOverflow();

// ── Axis calibration test hooks (test builds only) ────────────────────────────
// The transform itself is tested by calling OpenSkyhawk::axisCalApply() directly. These
// hooks exist to cover something that function-level test cannot: that HIDAxis::dispatch()
// actually *applies* it. That path is doubly hidden in test builds — the HID setters are
// no-op stubs, and the flash load is stubbed to a RAM clear so no calibration can be
// installed. Without both a writer and a reader, deleting the transform from dispatch()
// would leave every assertion passing.

void calSetForTest(const OpenSkyhawk::CalBlob& blob);

int16_t lastAxisValue();

uint8_t lastAxisIndex();

void resetAxisCapture();

uint8_t hidSendCount();

void resetHidSendCount();

// ── Calibration transport test hooks (test builds only) ───────────────────────
// The transport's safety property is that a rejected candidate is handed back to the relay
// byte-for-byte. Asserting that needs a capture on the UART side, which had no test seam.

bool feedCdcByte(uint8_t b);

void resetUartCapture();

size_t uartCaptureCount();

uint8_t uartCaptureByte(size_t index);

bool uartCaptureOverflow();

void calResetForTest();

bool calSessionOpen();

uint8_t calStreamAxis();

// ── Status-LED test hooks (test builds only) ──────────────────────────────────
// The pure state-selection + animation logic is exercised without GPIO, TinyUSB,
// or PL011 register reads by injecting inputs and reading back the resolved state /
// captured pin levels. Mirrors the feedByte/cdcCapture pattern above.

void statusInject(uint32_t now, bool mounted, uint32_t lastCdcRxMs, bool faultActive);

void statusResolve();

bool statusFaultStep(uint32_t now, bool rsrError, bool uartRxMoved);

LedState statusState();

Anim statusAnim();

bool statusRedLevel();

bool statusGreenLevel();

void statusResetForTest();
#endif

} // namespace SimGateway

#endif // ARDUINO_ARCH_RP2040