Skip to content

digital_in.hpp

IDigitalIn — a single digital input line behind the HAL (chunk R1b): a limit switch, a bumper, a jumper — any two-state sensor on an ADI port.

This header declares 1 type (7 members).

Extracted from include/shulib/hal/digital_in.hpp — this page is that header's documentation, reformatted, so it cannot disagree with the code. Prose about how to think about the API lives in the user guide; worked recipes live in the cookbook; this page is the complete, mechanical list of what exists.

Contents

class IDigitalIn

class IDigitalIn

One digital input line behind the HAL — a limit switch, a bumper, a jumper: any two-state sensor on an ADI port. The input sibling of IDigitalOut, and a seam with exactly one degree of freedom, which is why three things are deliberately absent and belong to the CONSUMER instead: * NO debouncing. A homing switch and a collision bumper want different filters, and this layer cannot know which it is serving — a time constant here would be an unmeasured constant chosen by the one layer with no idea what the switch is for. * NO edge detection. "Was it JUST pressed" is per-consumer state; put a hal::ButtonEdge above the seam, one per consumer, exactly as driver buttons do. * NO validity channel. A dead ADI port is indistinguishable from a working one at this level; catching a dead switch is a cross-check's job (homing travel limits), not this seam's. It is deliberately OUTSIDE the F4 runtime-interface freeze, and said out loud rather than left to be inferred: it was added ahead of any consumer, while the lift-homing question (switch or stall?) is still open, so it may still move. A real consumer is what would freeze it.

class, declared at include/shulib/hal/digital_in.hpp:58.

IDigitalIn::~IDigitalIn

virtual ~IDigitalIn() = default

The rule-of-five set plus the default constructor — six = defaults, none of which add behaviour, because this seam holds no state of its own. Spelled out in full because the suppression chain is easy to get wrong: a user-declared destructor suppresses only the implicit MOVE members (the copies survive it, their generation merely deprecated), re-declaring the moves is what would DELETE those copies, and declaring any constructor at all is what costs you the implicit default one. Writing only virtual ~IFoo() = default; therefore leaves a new interface still copyable, with every "move" of it quietly resolving to that copy. What copying a concrete IMPLEMENTATION means is that implementation's business — the interface makes no claim.

function, declared at include/shulib/hal/digital_in.hpp:69.

IDigitalIn::IDigitalIn

IDigitalIn() = default

Covered by the comment on ~IDigitalIn — one comment documents this run of special members.

function, declared at include/shulib/hal/digital_in.hpp:70.

IDigitalIn::IDigitalIn (overload 2)

IDigitalIn(const IDigitalIn&) = default

Covered by the comment on ~IDigitalIn — one comment documents this run of special members.

function, declared at include/shulib/hal/digital_in.hpp:71.

IDigitalIn::IDigitalIn (overload 3)

IDigitalIn(IDigitalIn&&) = default

Covered by the comment on ~IDigitalIn — one comment documents this run of special members.

function, declared at include/shulib/hal/digital_in.hpp:72.

IDigitalIn::operator=

IDigitalIn& operator=(const IDigitalIn&) = default

Covered by the comment on ~IDigitalIn — one comment documents this run of special members.

function, declared at include/shulib/hal/digital_in.hpp:73.

IDigitalIn::operator= (overload 2)

IDigitalIn& operator=(IDigitalIn&&) = default

Covered by the comment on ~IDigitalIn — one comment documents this run of special members.

function, declared at include/shulib/hal/digital_in.hpp:74.

IDigitalIn::state

[[nodiscard]] virtual bool state() const = 0

The line's current level, raw and unfiltered (a LEVEL, not an edge — per-consumer edge detection lives in ButtonEdge, above the seam; header note). What "true" means physically belongs to the mechanism that owns the line.

function, declared at include/shulib/hal/digital_in.hpp:80.

Design commentary, from the header

The header opens with the reasoning behind these shapes. It is reproduced here in full because a reference that only lists signatures teaches nobody why.

The header’s own reasoning — 38 lines
 IDigitalIn — a single digital input line behind the HAL (chunk R1b): a limit
 switch, a bumper, a jumper — any two-state sensor on an ADI port. The input
 sibling of IDigitalOut (digital_out.hpp), added by the same additive-sibling
 path (F1's IDigitalOut, R1a's IController).

 ── Built on an open question, and saying so ────────────────────────────────────────
 The lift-homing question (switch or stall?) was asked 2026-08-13 and is NOT
 answered. This seam exists on the "cheap now, expensive to discover at R3
 with the robot on the bench" ruling — it has NO consumer yet, which departs
 from F1's earned-interface standard deliberately and out loud. If the answer
 comes back "stall", this is a small unused sibling; that cost was accepted
 when the seam was ruled in. What keeps the shape honest: a digital input has
 exactly one degree of freedom, so there is nothing to guess at.

 Contract (each clause inherited from IDigitalOut's rulings, digital_out.hpp):
  * state() is the RAW LEVEL, now. What "true" means physically (pressed?
    released? beam broken?) is plumbing-dependent and belongs to the mechanism
    that owns the line, never to this seam.
  * NO debouncing, deliberately. A homing switch wants a different filter from
    a collision bumper, and the adapter cannot know which it is serving —
    a time constant baked in here would be an unmeasured constant in the one
    layer with no idea what the switch is for. Debounce is the consumer's.
  * NO edge detection, deliberately. "Was it JUST pressed" is per-consumer
    state: reuse hal::ButtonEdge (controller.hpp) above the seam, exactly as
    driver buttons do — never PROS's adi DigitalIn::get_new_press(), which
    CONSUMES the event so a second consumer silently misses every press
    (HA-121, the ADI sibling of HA-104).
  * NO validity channel, like IDigitalOut: a dead ADI port is
    indistinguishable from a working one at this seam. Detecting a dead
    switch is a cross-check's job (e.g. homing travel limits), not this
    seam's.

 NOT part of the F4 freeze (locked 2026-06-19 with the ten runtime
 interfaces). This is chunk R1b's addition, outside it — register row F14
 records the NON-freeze out loud (D2's lesson: silence in that register
 reads as "frozen"). Freeze trigger: a real consumer — F3's homing decision,
 if it comes back "switch".

Last updated 2026-08-15 — published from the main release branch, commit fa545ff. This site tracks releases, so between them it can lag the repository — that lag is deliberate, and it is what keeps the development log off the public site. For the current state of the code, see the repository.