Skip to content

Namespace OpenSkyhawk

Namespace List > OpenSkyhawk

Thin wrapper over Adafruit_ADS1115; see ADS1115.h .

Classes

Type Name
struct AccelPoint
One point on the acceleration curve (SwitecX25 form).
class AnalogInput
Continuous analog input — one analog PinRef , normalised to a 16-bit value 0..65535. Emits the smoothed value over CAN (MULTIPOS transport). Self-registers intoPanelGroup 'sInputBase list.
class AnalogMultiPos
Resistor-ladder multi-position selector — one analog PinRef , a different voltage per position. Emits the resolved position index 0..N-1 over CAN (MULTIPOS dispatch).
struct AxisCal
Captured endpoints for one axis, unsigned 0–65535 throughout.
struct CalBlob
The whole persisted calibration set, written and erased as one unit.
class DrumDisplay
Rolling-drum OLED readout. One instance == one OLED panel.
struct DrumFlag
Optional 2-state (or N-state) flag tape — hemisphere N/S · E/W, or a mode letter.
struct DrumGlyph
A fixed (non-rolling) glyph painted between digit columns — '.', ' ', ':' etc.
struct DrumReadout
Complete description of one rolling readout: its sources, geometry, glyphs, flag.
struct DrumSource
One DCS-BIOS digit source feeding a DrumReadout .
class FaultSource
A source of node faults — implemented by any object that can fault (#163).
struct GaugeCal
Value → position calibration for one gauge.
class HIDAxis
HID axis handler. Declared at sketch scope for each joystick axis.
class HIDButton
HID button handler. Declared at sketch scope for each button.
class HIDHatSwitch
HID hat switch handler. Declared at sketch scope for each hat switch.
struct HomeSensor
Home-sensor parameters ( HomeMode::SENSOR only).
class I2cHealth
Per-device I2C circuit breaker. Mix into any class that talks to an I2C device.
class I2cMux
Selects one downstream channel of a TCA9548A I2C multiplexer.
class InputBase
Abstract base for all hardware-polled input objects.
class LED
Digital LED output. Drives a pin based on a DCS-BIOS state value.
class MotorDriver
Common interface every motor/servo backend implements.
class MultiPosInput
Base for the MULTIPOS input family — selectors that emit an absolute position index 0..N-1 over CAN. Self-registers into PanelGroup 'sInputBase list.
class NeedleGauge
DCS-driven pointer gauge over any MotorDriver backend.
class OutputBase
Abstract base for all DCS-driven output objects.
class RotaryEncoder
Incremental quadrature encoder on two pins (A/B). Emits a signed relative value per detent over CAN — direction in the sign, magnitude set by the mode. Self-registers intoPanelGroup 'sInputBase list.
class ShiftBus
One shared SPI shift-register bus ('165 inputs + '595 outputs).
struct StepperConfig
Full per-instance stepper configuration. Authored per sketch (panel wiring).
class StepperMotor
Non-blocking instrument-gauge stepper driven through PinRef coils.
class Switch2Pos
Debounced 2-position switch. Self-registers into PanelGroup 'sInputBase list.
class Switch3Pos
Three-position switch (ON-OFF-ON / spring-centred) on two pins. Emits 0 / 1 / 2 over CAN (MULTIPOS dispatch).
class SwitchMultiPos
Multi-position rotary selector — N discrete pins, exactly one active at a time. Emits the active position index 0..N-1 over CAN (MULTIPOS dispatch).

Public Types

Type Name
enum uint8_t CalNackReason
NACK reasons. detail names the offending axis where one applies, else 0xFF.
enum uint8_t CalType
Message types. High bit set = device→client, so direction is readable in a capture.
enum uint8_t DrumFont
Glyph font size. Maps to a fixed monospace ProFont face.
enum uint8_t DrumScroll
Scroll behaviour per readout.
enum uint8_t EncoderMode
Relative-dispatch mode — picks the DCS-BIOS interface the bridge drives, hence the CAN frame + payload encoding this encoder uses per detent. Scoped enum.
enum uint8_t EncoderStepsPerDetent
Quadrature transitions per mechanical detent (match to the encoder). Scoped enum.
enum uint8_t HomeMode
How the driver establishes its zero reference at boot.
enum uint8_t LeadingZero
Leading-zero handling for a readout's high-order digit cells.
enum uint8_t StepPattern
Coil energising sequence.

Public Attributes

Type Name
constexpr uint8_t AXIS_CAL_SLOTS = 8
HID report axis slots. Fixed by the report descriptor, not by how many a cockpit populates.
constexpr uint8_t CAL_AXIS_NONE = 0xFF
RESET and the axis-selection fields use this to mean "all" / "none".
constexpr uint16_t CAL_ENVELOPE_BYTES = 10
magic 4 + type 1 + seq 1 + len 2 + crc 2
constexpr uint8_t CAL_FRAME_MAGIC = { 0xAA, 0x53, 0x4B, 0x43 }
constexpr uint32_t CAL_MAGIC = /* multi line expression */
Blob signature. Little-endian in flash, so a hexdump reads "OSKC".
constexpr uint16_t CAL_MAX_FRAME = [**CAL\_ENVELOPE\_BYTES**](namespaceOpenSkyhawk.md#variable-cal_envelope_bytes) + [**CAL\_MAX\_PAYLOAD**](namespaceOpenSkyhawk.md#variable-cal_max_payload)
constexpr uint16_t CAL_MAX_PAYLOAD = 82
CAL_DATA, the largest legal payload.
constexpr uint8_t CAL_PROTO_VERSION = 1
constexpr uint16_t CAL_VERSION = 1
Blob layout version.
const AccelPoint kSwitecDefaultAccel = /* multi line expression */
Default SwitecX25 acceleration table; fits the X27/VID-29/BKA-30 air-core family.
constexpr uint8_t kSwitecDefaultAccelN = 5

Public Static Attributes

Type Name
constexpr uint16_t ANALOG_NC = [**MultiPosInput::NO\_POSITION**](classOpenSkyhawk_1_1MultiPosInput.md#variable-no_position)
posVals[] sentinel: a position with no physical detent (no distinct voltage).
const float EASE = 0.30f
const uint32_t FRAME_MS = 16
const uint8_t KIND_DIGIT = 0
const uint8_t KIND_FLAG = 2
const uint8_t KIND_GLYPH = 1
const float PX_PER_MM = 4.35f
const float SETTLE_EPS = 0.02f
const float SNAP_LANDING = 1.5f

Public Functions

Type Name
NodeFaultCode aggregateFaults (const char ** detailOut=nullptr)
Roll up the registered fault sources into a single node fault code (#163).
uint16_t axisCalApply (const AxisCal & cal, uint16_t raw)
Map a raw axis reading through the two-segment calibration.
bool axisCalValid (const AxisCal & cal)
True when both segments have a non-zero divisor, i.e. the axis is calibrated.
void calBlobClear (CalBlob & blob)
Zero a blob so every axis reads as uncalibrated.
uint16_t calBlobCrc (const CalBlob & blob)
CRC of a blob's covered region, i.e. everything before the crc field itself.
void calBlobSeal (CalBlob & blob)
Stamp magic, version, and a fresh CRC onto a blob ahead of persisting it.
bool calBlobValid (const CalBlob & blob)
True when a blob carries the right signature, version, and checksum.
uint16_t calBuildFrame (uint8_t * out, uint16_t outCap, uint8_t type, uint8_t seq, const uint8_t * payload, uint16_t len)
Build a complete frame into a caller-supplied buffer.
uint16_t calCrc16 (const uint8_t * data, size_t len)
CRC-16/CCITT-FALSE — poly 0x1021, init 0xFFFF, no reflection, no final XOR.
bool calFrameCrcOk (const uint8_t * frame, uint16_t n)
Verify the CRC of a complete, already-assembled frame.
bool calLenValidForType (uint8_t type, uint16_t len)
Is len the only length thistype may legally carry?
StepperConfig makeX27Config (int16_t homePosition, int16_t parkPosition, int16_t minPos, int16_t maxPos, HomeMode home=HomeMode::STALL, bool homeSeekClockwise=false, HomeSensor sensor={ true, 5, 2000 }, bool wrap=false, uint8_t deadband=1, bool autoRecal=false, uint32_t recalDebounceMs=0, uint16_t stepsPerRev=1080, uint16_t rangeSteps=945, uint16_t homeStepUs=0)
Build a StepperConfig with the X27 air-core motor defaults filled in.

Public Static Functions

Type Name
long pow10l (uint8_t n)

Public Types Documentation

enum CalNackReason

NACK reasons. detail names the offending axis where one applies, else 0xFF.

enum OpenSkyhawk::CalNackReason {
    CAL_NACK_BAD_CRC = 0x01,
    CAL_NACK_BAD_LENGTH = 0x02,
    CAL_NACK_BAD_TYPE = 0x03,
    CAL_NACK_BAD_INDEX = 0x04,
    CAL_NACK_BAD_ORDER = 0x05,
    CAL_NACK_NO_SESSION = 0x06,
    CAL_NACK_NO_STORAGE = 0x07,
    CAL_NACK_BAD_DEADZONE = 0x08
};

enum CalType

Message types. High bit set = device→client, so direction is readable in a capture.

enum OpenSkyhawk::CalType {
    CAL_T_HELLO = 0x01,
    CAL_T_GET_CAL = 0x02,
    CAL_T_SESSION_OPEN = 0x03,
    CAL_T_SESSION_CLOSE = 0x04,
    CAL_T_COMMIT = 0x05,
    CAL_T_RESET = 0x06,
    CAL_T_KEEPALIVE = 0x07,
    CAL_T_STREAM_SELECT = 0x08,
    CAL_T_HELLO_ACK = 0x81,
    CAL_T_CAL_DATA = 0x82,
    CAL_T_SESSION_ACK = 0x83,
    CAL_T_ACK = 0x84,
    CAL_T_NACK = 0x85,
    CAL_T_RAW = 0x86
};

enum DrumFont

Glyph font size. Maps to a fixed monospace ProFont face.

enum OpenSkyhawk::DrumFont {
    SMALL = 0,
    LARGE = 1
};

Note:

SMALL = u8g2_font_profont22_mr, LARGE = u8g2_font_profont29_mr (mono, ASCII). Mono guarantees the flag glyph ('N'/'S'/'E'/'W') is no wider than a digit cell.


enum DrumScroll

Scroll behaviour per readout.

enum OpenSkyhawk::DrumScroll {
    EASE_ONLY = 0,
    SNAP_SETTLE = 1
};

Note:

SNAP_SETTLE adds the prototype-missing jump handling: deltas above the readout's snapThreshold teleport the tape near the target, then ease the final step, so a sudden 130→250 KIAS change doesn't spin every wheel through 120 intermediate values.


enum EncoderMode

Relative-dispatch mode — picks the DCS-BIOS interface the bridge drives, hence the CAN frame + payload encoding this encoder uses per detent. Scoped enum.

enum OpenSkyhawk::EncoderMode {
    Rel,
    Dir
};

enum EncoderStepsPerDetent

Quadrature transitions per mechanical detent (match to the encoder). Scoped enum.

enum OpenSkyhawk::EncoderStepsPerDetent {
    One = 1,
    Two = 2,
    Four = 4,
    Eight = 8
};

enum HomeMode

How the driver establishes its zero reference at boot.

enum OpenSkyhawk::HomeMode {
    STALL,
    SENSOR
};

enum LeadingZero

Leading-zero handling for a readout's high-order digit cells.

enum OpenSkyhawk::LeadingZero {
    Keep = 0,
    Suppress = 1
};

Note:

Suppress blanks the high-order zero cells down to the target's significant-digit count (units always shows, so 0 renders "0"); animation is unchanged. Keep is fixed width.


enum StepPattern

Coil energising sequence.

enum OpenSkyhawk::StepPattern {
    SWITEC_6STATE,
    FULL_4STATE
};

Public Attributes Documentation

variable AXIS_CAL_SLOTS

HID report axis slots. Fixed by the report descriptor, not by how many a cockpit populates.

constexpr uint8_t OpenSkyhawk::AXIS_CAL_SLOTS;

variable CAL_AXIS_NONE

RESET and the axis-selection fields use this to mean "all" / "none".

constexpr uint8_t OpenSkyhawk::CAL_AXIS_NONE;

variable CAL_ENVELOPE_BYTES

magic 4 + type 1 + seq 1 + len 2 + crc 2

constexpr uint16_t OpenSkyhawk::CAL_ENVELOPE_BYTES;

variable CAL_FRAME_MAGIC

constexpr uint8_t OpenSkyhawk::CAL_FRAME_MAGIC[4];

Frame lead-in. 0xAA leads all non-DCS data on this link, matching the HID frame magic. Distinct from CAL_MAGIC above, which signs the stored blob rather than a wire frame.


variable CAL_MAGIC

Blob signature. Little-endian in flash, so a hexdump reads "OSKC".

constexpr uint32_t OpenSkyhawk::CAL_MAGIC;

variable CAL_MAX_FRAME

constexpr uint16_t OpenSkyhawk::CAL_MAX_FRAME;

variable CAL_MAX_PAYLOAD

CAL_DATA, the largest legal payload.

constexpr uint16_t OpenSkyhawk::CAL_MAX_PAYLOAD;

variable CAL_PROTO_VERSION

constexpr uint8_t OpenSkyhawk::CAL_PROTO_VERSION;

variable CAL_VERSION

Blob layout version.

constexpr uint16_t OpenSkyhawk::CAL_VERSION;

Note:

A mismatch means "absent" — every axis falls back to identity and flash is left untouched until the user commits. No migration and no auto-rewrite: a downgrade-then-upgrade cycle would silently destroy data.


variable kSwitecDefaultAccel

Default SwitecX25 acceleration table; fits the X27/VID-29/BKA-30 air-core family.

const AccelPoint OpenSkyhawk::kSwitecDefaultAccel;

variable kSwitecDefaultAccelN

constexpr uint8_t OpenSkyhawk::kSwitecDefaultAccelN;

Public Static Attributes Documentation

variable ANALOG_NC

posVals[] sentinel: a position with no physical detent (no distinct voltage).

constexpr uint16_t OpenSkyhawk::ANALOG_NC;

The uint16_t analog of SwitchMultiPos's PIN_NC — same "this position index has no physical input" role, but a different sentinel because an analog ladder is an array of ADC values (uint16_t), not PinRefs. Kept == MultiPosInput::NO_POSITION (both 0xFFFF) so there is one sentinel value across the MULTIPOS family.


variable EASE

const float OpenSkyhawk::EASE;

variable FRAME_MS

const uint32_t OpenSkyhawk::FRAME_MS;

variable KIND_DIGIT

const uint8_t OpenSkyhawk::KIND_DIGIT;

variable KIND_FLAG

const uint8_t OpenSkyhawk::KIND_FLAG;

variable KIND_GLYPH

const uint8_t OpenSkyhawk::KIND_GLYPH;

variable PX_PER_MM

const float OpenSkyhawk::PX_PER_MM;

variable SETTLE_EPS

const float OpenSkyhawk::SETTLE_EPS;

variable SNAP_LANDING

const float OpenSkyhawk::SNAP_LANDING;

Public Functions Documentation

function aggregateFaults

Roll up the registered fault sources into a single node fault code (#163).

NodeFaultCode OpenSkyhawk::aggregateFaults (
    const char ** detailOut=nullptr
) 

Walks FaultSource::head() and returns the first source reporting a non-NONE faultCode(); if detailOut is non-null it is set to that source's faultDetail(). Returns NodeFaultCode::NONE when every source is healthy. *detailOut is always a non-null string ("" when healthy or a source returns null) — callers never null-check.

Note:

Iteration is registry order = reverse construction order (the intrusive list pushes at head), so the last-constructed fault source has priority. With one active fault at a time on the wire this rarely matters; a node with concurrent faults reports the head-most.

Note:

Cheap/const — sources report cached state only. Called on the periodic health path.

Parameters:

  • detailOut Optional out-param for the local DiagSerial detail string (never null on return).

Returns:

The primary NodeFaultCode, or NONE if no source is faulted.


function axisCalApply

Map a raw axis reading through the two-segment calibration.

uint16_t OpenSkyhawk::axisCalApply (
    const AxisCal & cal,
    uint16_t raw
) 

Parameters:

  • cal Endpoints for this axis.
  • raw Unsigned 0–65535 as emitted by the node.

Returns:

Unsigned 0–65535, with cal.centre landing exactly on 32768.

Returns raw unchanged when the axis is uncalibrated, so an unwritten blob behaves identically to a build without this feature.

Note:

Integer only, by design — the arithmetic must be reproducible exactly, and a curve would stack with the per-aircraft curves DCS already applies.

Note:

The uint32_t cast must sit on the multiply operand. Worst case is 65534 × 32768 = 2 147 418 112, inside uint32_t with 2× headroom. int is 32-bit on RP2040 so the wrong form would work here by accident; the explicit cast is the portable contract.

Note:

65535 is reachable only via the upper clamp — the upper segment's arithmetic tops out at 65534. Both map to +32767 after the caller's −32768, so this is correct, but it is the kind of asymmetry someone will otherwise "fix".


function axisCalValid

True when both segments have a non-zero divisor, i.e. the axis is calibrated.

bool OpenSkyhawk::axisCalValid (
    const AxisCal & cal
) 

Parameters:

  • cal Endpoints to check.

Returns:

true if min < centre < max allowing for the deadzone.

Note:

This doubles as the calibrated/uncalibrated predicate — there is no stored validity flag, because a flag could only duplicate or contradict this. An all-zero blob (.bss, never loaded) and an all-0xFF blob (erased flash) both fail it, so both fail closed to identity.

Note:

Widened to uint32_t deliberately. The obvious min < centre - deadzone underflows on uint16_t when deadzone > centre. The wire protocol rejects a non-zero deadzone, but this guard's whole job is preventing a divide-by-zero in axisCalApply(), so it must not depend on a check one layer up.


function calBlobClear

Zero a blob so every axis reads as uncalibrated.

void OpenSkyhawk::calBlobClear (
    CalBlob & blob
) 

Parameters:

  • blob Blob to clear.

Note:

Clears RAM only. Nothing here writes flash.


function calBlobCrc

CRC of a blob's covered region, i.e. everything before the crc field itself.

uint16_t OpenSkyhawk::calBlobCrc (
    const CalBlob & blob
) 

Parameters:

  • blob Blob to checksum.

Returns:

The CRC to store in, or compare against, blob.crc.


function calBlobSeal

Stamp magic, version, and a fresh CRC onto a blob ahead of persisting it.

void OpenSkyhawk::calBlobSeal (
    CalBlob & blob
) 

Parameters:

  • blob Blob whose axes are already populated.

function calBlobValid

True when a blob carries the right signature, version, and checksum.

bool OpenSkyhawk::calBlobValid (
    const CalBlob & blob
) 

Parameters:

  • blob Blob as read from storage.

Returns:

true if the blob should be trusted.


function calBuildFrame

Build a complete frame into a caller-supplied buffer.

uint16_t OpenSkyhawk::calBuildFrame (
    uint8_t * out,
    uint16_t outCap,
    uint8_t type,
    uint8_t seq,
    const uint8_t * payload,
    uint16_t len
) 

Parameters:

  • out Destination, at least CAL_ENVELOPE_BYTES + len bytes.
  • outCap Capacity of out.
  • type Message type.
  • seq Sequence byte — echoed from the request, or a counter for unsolicited RAW.
  • payload Payload bytes; may be nullptr when len is 0.
  • len Payload length. Must satisfy calLenValidForType().

Returns:

Bytes written, or 0 if the arguments are inconsistent or out is too small.


function calCrc16

CRC-16/CCITT-FALSE — poly 0x1021, init 0xFFFF, no reflection, no final XOR.

uint16_t OpenSkyhawk::calCrc16 (
    const uint8_t * data,
    size_t len
) 

Parameters:

  • data Bytes to cover.
  • len Byte count.

Returns:

The CRC.

Note:

Canonical check: "123456789" → 0x29B1. Init is 0xFFFF rather than 0x0000 so that leading zero bytes change the result — an all-zero blob is a realistic corruption mode, and a 0x0000 init would not distinguish it from a shorter all-zero one. Bitwise and table-free: ~70 bytes of input costs a few microseconds, irrelevant beside the ~45 ms sector erase it protects.


function calFrameCrcOk

Verify the CRC of a complete, already-assembled frame.

bool OpenSkyhawk::calFrameCrcOk (
    const uint8_t * frame,
    uint16_t n
) 

Parameters:

  • frame Whole frame including magic and trailing CRC.
  • n Frame length in bytes.

Returns:

true if the trailing CRC matches the computed one.

Note:

Coverage is TYPESEQLENPAYLOAD — the magic is excluded, and so is the CRC field itself. Checksumming constant bytes adds no detection power.


function calLenValidForType

Is len the only length thistype may legally carry?

bool OpenSkyhawk::calLenValidForType (
    uint8_t type,
    uint16_t len
) 

Parameters:

  • type Message type byte.
  • len Candidate payload length, as read off the wire.

Returns:

true if the pair is legal.

This is the framing-layer gate, and it is checked before the payload is buffered. len is read before the CRC can be verified, so on a false frame it is noise: a stray magic in DCS-BIOS text can decode a length near 65535, and a receiver that waits for that many bytes stalls. Every type therefore has an exact length rather than a shared bound.

Note:

There are no variable-length types. COMMIT carries exactly one axis, so the rule is uniform: one legal length per type, no exception to state or to get wrong. An earlier draft let COMMIT batch up to eight axes, which allowed a batch to name the same axis twice with different values and silently apply the last.

Note:

An unknown type is rejected. Protocol versions must match — HELLO_ACK carries proto for exactly that — so an unrecognised type is an error, not something to skip.


function makeX27Config

Build a StepperConfig with the X27 air-core motor defaults filled in.

StepperConfig OpenSkyhawk::makeX27Config (
    int16_t homePosition,
    int16_t parkPosition,
    int16_t minPos,
    int16_t maxPos,
    HomeMode home=HomeMode::STALL,
    bool homeSeekClockwise=false,
    HomeSensor sensor={ true, 5, 2000 },
    bool wrap=false,
    uint8_t deadband=1,
    bool autoRecal=false,
    uint32_t recalDebounceMs=0,
    uint16_t stepsPerRev=1080,
    uint16_t rangeSteps=945,
    uint16_t homeStepUs=0
) 

Bakes the motor-invariant fields — stepsPerRev, pattern (SWITEC_6STATE), and the default SwitecX25 accel table — so a sketch specifies only the per-gauge wiring/travel. Shared by every X27 / VID-29 / BKA-30 gauge; override any default for a specific panel.

Parameters:

  • homePosition step index at the home reference.
  • parkPosition rest position after homing.
  • minPos lower moveTo travel clamp (ignored if wrap).
  • maxPos upper moveTo travel clamp (ignored if wrap).
  • home homing strategy. Default STALL.
  • homeSeekClockwise seek direction. Default false.
  • sensor home-sensor params (SENSOR mode). Default active-low, 5 ms, 2000 steps.
  • wrap continuous-rotation gauge. Default false.
  • deadband anti-jitter band, steps. Default 1.
  • autoRecal re-zero on sensor crossing. Default false.
  • recalDebounceMs minimum interval between auto-recals. Default 0.
  • stepsPerRev full revolution in steps. Default 1080 (X27/BKA datasheet, 1/3°/step).
  • rangeSteps mechanical stop-to-stop travel in steps = STALL home distance. Default 945 (X27.589 ~315°); set per gauge (e.g. 960 for a 320° BKA-30).
  • homeStepUs homing seek rate µs/step. Default 0 → library default (2000 ≈ 500 steps/s). Keep under the motor start-stop rate (~774 steps/s) or the seek slips.

Returns:

Populated StepperConfig.


Public Static Functions Documentation

function pow10l

static long OpenSkyhawk::pow10l (
    uint8_t n
) 


The documentation for this class was generated from the following file Firmware/Libraries/DrumDisplay/DrumDisplay.cpp