Skip to content

PinsModule

Source: PinsModule.h

Claim

struct Claim
src/core/PinsModule.h:74

Public Attributes

uint8_t gpio

char owner

char role

constchar * severity

constchar * reason

platform::GpioLiveState live

PinListSource

struct PinListSource
src/core/PinsModule.h:70

Inherits: ListSource

The pin ownership map: a ListSource over a fixed snapshot rebuilt on tick1s.

A claim is one GPIO staked by one control; multiple claims on the same GPIO are kept (a conflict must stay visible, not be merged away). No allocation — a fixed Claim[kMaxClaims], filled or left at count 0.

Public Attributes

Claim claims_

uint8_t count_ = 0

Public Methods

inline void refresh()

inline void flagConflicts()

inline uint8_t listRowCount() const override

inline void writeListRow(JsonSink & sink, uint8_t row) const override

inline void writeListRowDetail(JsonSink & sink, uint8_t row) const override

Public Static Attributes

constexpruint8_t kMaxClaims = 64

Public Static Methods

static inline constchar * driveLabel(uint8_t cap)

static inline constchar * dirLabel(const platform::GpioLiveState & live)

PinsModule

class PinsModule
src/core/PinsModule.h:50

Inherits: MoonModule

A core, domain-neutral diagnostic that shows which module owns each GPIO, for what role, whether that pin is safe for it, and what it's doing right now — the device's pin ownership map, keyed by physical GPIO the way an OS Device Manager, a Tasmota template, or a GPIOViewer diagram is.

It walks the live module tree and collects every claimed pin: each ControlType::Pin control (a mic's sckPin/wsPin/sdPin, an Ethernet PHY's ethMdcGpio, a driver's loopbackTxPin) and each "pins" text control (an LED driver's "18,19,20" lane CSV). Per claim it adds a severity flag (a claim on a reserved/strap/input-only pin, or a double-claim, via platform::gpioCapability) and the live state (level + drive strength, via platform::gpioLiveState — the see-the-wire HAL check). A disabled module's pins drop out (the map reflects release-on-disable intent).

One nested list: pins. Each row is a claimed GPIO (gpio, owner, role); a GPIO claimed by more than one control shows the first owner in the summary and every claimant in the row detail, so a double-claim is visible at a glance — the exact class of bug the GPIO-46 loopback corruption was (an output role driven onto a strap). Surfacing only: this reads the tree, it does not arbitrate. The controls are already the pin registry; this module is a reader over them, holding no state of its own.

Inversion vs the central-manager pattern. MoonLight's ModuleIO (https://github.com/MoonModules/MoonLight) is the central pin manager — it owns a JSON pin table and assigns GPIOs. projectMM inverts that: each module owns its own pins (as its own controls), and this one central module only observes and coordinates. So the reusable idea taken from ModuleIO is its per-pin report — owner + usage — not its ownership mechanism; here the owner and role are read back out of the live controls, never from a central table. The role column is name-derived (see roleFor), projectMM's equivalent of ModuleIO's usage enum without a central vocabulary.

Fixed System module. Wired by code as a child of SystemModule in main.cpp (like Tasks and I2cScan), not user-added — you don't delete the pin map. Base Generic role so no container accepts it as a user-editable child; markWiredByCode() exempts it from the persistence trim. Read-only: no editable controls. The list refreshes on [tick1s()] (a periodic sample, never the hot path), so a live pin change shows on the next second with no reboot. The list uses ControlType::List + ListSource, the read-only data-source/adapter shape (UITableView's data source, Qt's QAbstractItemModel) as TasksModule.

Public Methods

virtual inline void defineControls() override : defineControls MUST be idempotent and pure: only controls_.clear() + controls_.addX().

virtual inline void tick1s() override : Re-walk the tree once a second (off the hot path) to rebuild the claim map.