Namespace 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 = 8HID report axis slots. Fixed by the report descriptor, not by how many a cockpit populates. |
| constexpr uint8_t | CAL_AXIS_NONE = 0xFFRESET and the axis-selection fields use this to mean "all" / "none". |
| constexpr uint16_t | CAL_ENVELOPE_BYTES = 10magic 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 = 82CAL_DATA, the largest legal payload. |
| constexpr uint8_t | CAL_PROTO_VERSION = 1 |
| constexpr uint16_t | CAL_VERSION = 1Blob 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:
detailOutOptional 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:
calEndpoints for this axis.rawUnsigned 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:
calEndpoints 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:
blobBlob 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:
blobBlob 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:
blobBlob whoseaxesare already populated.
function calBlobValid
True when a blob carries the right signature, version, and checksum.
bool OpenSkyhawk::calBlobValid (
const CalBlob & blob
)
Parameters:
blobBlob 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:
outDestination, at leastCAL_ENVELOPE_BYTES + lenbytes.outCapCapacity ofout.typeMessage type.seqSequence byte — echoed from the request, or a counter for unsolicited RAW.payloadPayload bytes; may be nullptr whenlenis 0.lenPayload 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:
dataBytes to cover.lenByte 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:
frameWhole frame including magic and trailing CRC.nFrame length in bytes.
Returns:
true if the trailing CRC matches the computed one.
Note:
Coverage is TYPE‖SEQ‖LEN‖PAYLOAD — 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:
typeMessage type byte.lenCandidate 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:
homePositionstep index at the home reference.parkPositionrest position after homing.minPoslower moveTo travel clamp (ignored if wrap).maxPosupper moveTo travel clamp (ignored if wrap).homehoming strategy. Default STALL.homeSeekClockwiseseek direction. Default false.sensorhome-sensor params (SENSOR mode). Default active-low, 5 ms, 2000 steps.wrapcontinuous-rotation gauge. Default false.deadbandanti-jitter band, steps. Default 1.autoRecalre-zero on sensor crossing. Default false.recalDebounceMsminimum interval between auto-recals. Default 0.stepsPerRevfull revolution in steps. Default 1080 (X27/BKA datasheet, 1/3°/step).rangeStepsmechanical 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).homeStepUshoming 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