Skip to content

I2cScanModule

Source: I2cScanModule.h

I2cScanModule

class I2cScanModule
src/core/I2cScanModule.h:48

Inherits: MoonModule

A core, domain-neutral diagnostic that scans an I2C bus and reports which device addresses ACK — the standard i2cdetect operation, surfaced in the UI.

It is the bring-up tool for any I2C peripheral (an audio codec, a sensor, a port expander): set the bus pins, press scan, read off the addresses present, confirming wiring before a driver tries to talk to the device. Pressing scan probes the bus on the sda / scl pins and lists the 7-bit addresses found in result.

Same shape as DevicesModule (a momentary scan button → results), one rung simpler: the bus is local (no persisted list, no live age-out), so a single read-only result string suffices instead of a ListSource. Scan state ("N devices found", "set sda + scl pins first") reports through the standard setStatus() channel.

Fixed System module. Wired by code as a child of SystemModule in main.cpp — a hardware-inspection tool that is always available on every board, not user-added (you don't add a bus scanner, it's part of the device's bring-up toolkit). It stays passive until the user presses scan: no bus is opened and no pins are driven at boot. The pins default to GPIO21/22, the Arduino-ESP32 core's conventional I2C pair, so the control pre-fills a sensible starting point on a classic ESP32 (the pins route through the GPIO matrix, so they're a convention, not fixed hardware); a board with a fixed bus overrides them as a control-value default in its catalog entry (such as the S31's sda:51, scl:50).

How it works: the probe is platform::i2cScan(sda, scl, out, maxOut) (declared in platform.h), a self-contained seam that opens a temporary I2C master bus on the given pins, probes every 7-bit address (0x010x77), writes the ACKing addresses into the caller's buffer, and tears the bus down. Opening its own short-lived bus (rather than borrowing one) means the scan never conflicts with a bus another driver owns — the ES8311 codec on the ESP32-S31 holds its own bus, and the scan probes the same pins independently between codec operations. On a target without an I2C bus (an I2C-less ESP32, or desktop) the seam returns kI2cBusUnavailable, so the scan reports "bus unavailable" rather than a misleading "0 devices found" — the 0 is reserved for a real scan where nothing ACKed.

Prior art: the bus-scan-as-a-feature mirrors MoonLight's I2C scan diagnostic; the seam name and probe range follow the Linux i2c-tools``i2cdetect convention (https://manpages.debian.org/i2c-tools/i2cdetect.8.en.html).

I2cScanModule card

Public Methods

virtual inline void defineControls() override : Respects the enabled toggle (the default): disabling it releases its bus pins in the pin ownership map (and re-claims them on enable), so a user can free GPIO21/22 for another module by switching the scanner off.

virtual inline void onControlChanged(constchar *) override : Cheap per-control reaction, tier 1 of the three-tier control-change split (mirrors MoonLight's onUpdate / requestMappings / onSizeChanged; see architecture.md § Rebuild propagation).