OXRecorder::OXSwitchManager
GPIO switch monitoring — debounced state + long-press detection
Overview
OXSwitchManager watches one or more switches on GPIO pins and
reports two things: debounced press/release transitions
(for on/off behavior) and long-press events (a button held
for a configurable duration, e.g. 5 or 10 seconds). Callbacks receive the
GPIO pin, so one handler can serve several switches.
- General-purpose: momentary push-buttons (long-press actions) or plain on/off switches.
- Configurable per switch: pin, polarity (active-high / active-low), internal pull-up, long-press duration, debounce window.
- Long-press fires once, the moment the hold reaches the threshold — it does not wait for release.
- Cooperative: register switches, then pump
poll(millis())fromloop().
Declared in include/OXSwitchManager.h; portable core in
src/OXSwitchManager.cpp; the GPIO backend in
src/gpio/EspGpioInput.cpp. This is the detection engine behind
OXConfigManager's reset feature.
SwitchConfig
Describes one monitored switch. The addSwitch(pin, longPressMs) convenience overload fills these with active-low + pull-up defaults (a button to GND).
| Field | Type | Default | Meaning |
|---|---|---|---|
pin | int | 0 | GPIO to monitor. |
activeHigh | bool | true | Level that means "pressed". true = switch to 3V3; false = switch to GND. |
usePullup | bool | false | Enable the MCU internal pull-up (typical for an active-low switch to GND). |
longPressMs | uint32_t | 5000 | Hold time that counts as a long press. |
debounceMs | uint32_t | 30 | Contact debounce window; the level must be stable this long to register. |
API reference
bool begin()
Brings up the manager (obtains the default GPIO input on-device). Returns false if no input device is available. Call before addSwitch().
bool addSwitch(const SwitchConfig &cfg)
bool addSwitch(int pin, uint32_t longPressMs)
Starts monitoring a switch. The convenience overload assumes a momentary button to GND (active-low, pull-up). Returns false if the table is full (max 8) or no input device is set. Re-adding the same pin replaces its config.
| Parameter | Type | Meaning |
|---|---|---|
pin | int | GPIO to monitor. |
longPressMs | uint32_t | Hold time for the long-press event, e.g. 5000 or 10000. |
void onLongPress(SwitchLongPressCallback cb, void *ctx = nullptr)
Registers the long-press handler void(int pin, void *ctx), fired once when any tracked switch reaches its longPressMs. This is the switchLongPressDetected(pin) hook.
void onStateChange(SwitchStateCallback cb, void *ctx = nullptr)
Registers the state handler void(int pin, bool pressed, void *ctx), fired on every debounced press/release transition — use it for on/off switches.
size_t poll(uint32_t nowMs)
Samples all switches, runs debounce, and fires callbacks. Call regularly from loop() with millis(). Returns the number of switches whose debounced state changed this call.
bool isPressed(int pin) const
Current debounced state of a tracked pin (false if untracked).
uint32_t heldMs(int pin, uint32_t nowMs) const
How long the pin has been continuously pressed, in ms (0 if released/untracked) — handy for a long-press progress indicator.
Examples
Try it
Flash with pio run -e esp32-s3-super-mini -t upload && pio device monitor. The debounce + long-press logic is covered on the host by pio test -e native (via a fake GPIO input) — no hardware needed for logic changes.
1. Long-press action
#include <Arduino.h>
#include "OXSwitchManager.h"
#include "OXLog.h"
using namespace OXRecorder;
OXSwitchManager switches;
void onLongPress(int pin, void *ctx) {
OXLog::info("long press on GPIO%d", pin);
}
void setup() {
OXLog::begin(115200);
switches.begin();
switches.addSwitch(5, 5000); // GPIO5, 5 s — button to GND
switches.onLongPress(onLongPress);
}
void loop() {
switches.poll(millis());
delay(10);
}
2. On/off switch
void onState(int pin, bool pressed, void *ctx) {
OXLog::info("GPIO%d is now %s", pin, pressed ? "ON" : "OFF");
}
// ... in setup(): switches.onStateChange(onState);
3. Custom polarity (button to 3V3)
SwitchConfig cfg;
cfg.pin = 7;
cfg.activeHigh = true; // pressed = HIGH
cfg.usePullup = false; // external pull-down on the board
cfg.longPressMs = 10000; // 10 s
switches.addSwitch(cfg);
Notes
- Pump regularly. Long-press and debounce timing come from the
millis()you pass topoll(); keeploop()non-blocking. - Boot state is seeded.
addSwitch()reads the pin immediately so a switch already held at power-on doesn't fire a spurious transition. - Up to 8 switches per manager (
kMaxSwitches).