95 static inline void set_led(uint8_t pin,
bool on)
97 digitalWrite(pin, on ? LOW : HIGH);
106 pinMode(pin, OUTPUT);
132 bool testPin(uint8_t pin,
Type type,
const char *label =
nullptr)
const
134 const char *nm = (label && *label) ? label :
"PIN";
138 return _testShorted(pin, nm,
false) & _testOpen(pin, nm,
false) & _testDriveRead(pin, nm);
141 return _testShorted(pin, nm,
false) & _testOpen(pin, nm,
false);
144 return _testShorted(pin, nm,
false) & _testDriveRead(pin, nm);
147 return _testOpenDrain(pin, nm);
150 return _testAdc(pin, nm);
153 return _testI2cLineCheck(pin, nm,
"SDA");
156 return _testI2cLineCheck(pin, nm,
"SCL");
159 return _testDriveRead(pin, nm);
163 return _testShorted(pin, nm,
true) & _testOpen(pin, nm,
true);
166 return _testUartTx(pin, nm) & _testOpen(pin, nm,
false);
169 return _testShorted(pin, nm,
false) & _testOpen(pin, nm,
false);
173 g_serialIO.
sprintf(pstTestPinsMri::MSG_UNKNOWN_TYPE, nm, pin);
190 g_serialIO.
print(pstTestPinsMri::MSG_MCP_WARN);
193 g_serialIO.
sprintf(pstTestPinsMri::MSG_MCP_HDR, name ? name :
"MCP_PIN", mcpPin);
197 pMcp->
pullUp(mcpPin,
true);
203 g_serialIO.
print(pstTestPinsMri::MSG_MCP_GND);
207 g_serialIO.
print(pstTestPinsMri::MSG_MCP_FLOAT);
219 bool testOpen(uint8_t pin,
const char *label =
nullptr,
bool gentle =
false)
const
221 return _testOpen(pin, label ? label :
"NET", gentle);
231 bool testShorted(uint8_t pin,
const char *label =
nullptr,
bool gentle =
false)
const
233 return _testShorted(pin, label ? label :
"NET", gentle);
248 bool _testUartTx(uint8_t pin,
const char *label)
const
250 if (_isInputOnly(pin))
252 g_serialIO.
sprintf(pstTestPinsMri::MSG_INPUT_ONLY, label ? label :
"PIN", pin);
255 pinMode(pin, OUTPUT);
256 digitalWrite(pin, HIGH);
258 return _testShorted(pin, label ? label :
"PIN",
false) & _testDriveRead(pin, label ? label :
"PIN");
266 static bool _isInputOnly(uint8_t pin)
268 return (pin >= 34 && pin <= 39);
276 static bool _hasInternalPulls(uint8_t pin)
278 return !_isInputOnly(pin);
300 bool _testOpen(uint8_t pin,
const char *name,
bool gentle =
false)
const
302 g_serialIO.
sprintf(pstTestPinsMri::MSG_OPEN_HDR, name, pin);
304 if (!_hasInternalPulls(pin))
306 g_serialIO.
sprintf(pstTestPinsMri::MSG_NO_NUDGE, name, pin);
312 pinMode(pin, INPUT_PULLUP);
314 int up = digitalRead(pin);
315 pinMode(pin, INPUT_PULLDOWN);
317 int dn = digitalRead(pin);
319 if (up == HIGH && dn == LOW)
321 g_serialIO.
print(pstTestPinsMri::MSG_OPEN_PASS);
324 if (up == LOW && dn == LOW)
326 g_serialIO.
sprintf(pstTestPinsMri::MSG_STUCK_GND, name, pin);
329 if (up == HIGH && dn == HIGH)
331 g_serialIO.
sprintf(pstTestPinsMri::MSG_STUCK_VCC, name, pin);
334 g_serialIO.
sprintf(pstTestPinsMri::MSG_OPEN_SUSPECT, name, pin, up, dn);
342 int idle = digitalRead(pin);
343 pinMode(pin, INPUT_PULLUP);
345 int up = digitalRead(pin);
350 g_serialIO.
print(pstTestPinsMri::MSG_OPEN_PASS);
354 g_serialIO.
sprintf(pstTestPinsMri::MSG_OPEN_SUSPECT, name, pin, idle, up);
378 bool _testShorted(uint8_t pin,
const char *name,
bool gentle =
false)
const
380 g_serialIO.
sprintf(pstTestPinsMri::MSG_SHORT_HDR, name, pin);
381 if (!_hasInternalPulls(pin))
383 g_serialIO.
sprintf(pstTestPinsMri::MSG_NO_NUDGE, name, pin);
389 pinMode(pin, INPUT_PULLUP);
391 int up = digitalRead(pin);
392 pinMode(pin, INPUT_PULLDOWN);
394 int dn = digitalRead(pin);
395 if (up == LOW && dn == LOW)
397 g_serialIO.
sprintf(pstTestPinsMri::MSG_STUCK_GND, name, pin);
400 if (up == HIGH && dn == HIGH)
402 g_serialIO.
sprintf(pstTestPinsMri::MSG_STUCK_VCC, name, pin);
405 g_serialIO.
print(pstTestPinsMri::MSG_SHORT_PASS);
413 int idle = digitalRead(pin);
414 pinMode(pin, INPUT_PULLUP);
416 int up = digitalRead(pin);
421 g_serialIO.
print(pstTestPinsMri::MSG_SHORT_PASS);
424 g_serialIO.
sprintf(pstTestPinsMri::MSG_STUCK_GND, name, pin);
440 bool _testDriveRead(uint8_t pin,
const char *name)
const
442 if (_isInputOnly(pin))
444 g_serialIO.
sprintf(pstTestPinsMri::MSG_INPUT_ONLY, name, pin);
447 g_serialIO.
sprintf(pstTestPinsMri::MSG_DRIVE_HDR, name, pin);
448 pinMode(pin, OUTPUT);
450 digitalWrite(pin, HIGH);
452 int rH = digitalRead(pin);
453 digitalWrite(pin, LOW);
455 int rL = digitalRead(pin);
457 if (rH == HIGH && rL == LOW)
459 g_serialIO.
print(pstTestPinsMri::MSG_DRIVE_PASS);
462 g_serialIO.
sprintf(pstTestPinsMri::MSG_DRIVE_FAIL, name, pin, rH, rL);
477 bool _testOpenDrain(uint8_t pin,
const char *name)
const
479 if (_isInputOnly(pin))
481 g_serialIO.
sprintf(pstTestPinsMri::MSG_INPUT_ONLY, name, pin);
484 g_serialIO.
sprintf(pstTestPinsMri::MSG_OD_HDR, name, pin);
486 pinMode(pin, OUTPUT);
487 digitalWrite(pin, LOW);
489 int low = digitalRead(pin);
491 pinMode(pin, INPUT_PULLUP);
493 int hi = digitalRead(pin);
494 if (low == LOW && hi == HIGH)
496 g_serialIO.
print(pstTestPinsMri::MSG_OD_PASS);
499 g_serialIO.
sprintf(pstTestPinsMri::MSG_OD_FAIL, name, pin, low, hi);
513 bool _testAdc(uint8_t pin,
const char *name)
const
515 g_serialIO.
sprintf(pstTestPinsMri::MSG_ADC_HDR, name, pin);
516 analogSetPinAttenuation(pin, ADC_11db);
519 for (
int i = 0; i < N; ++i)
521 sumMv += analogReadMilliVolts(pin);
525 g_serialIO.
sprintf(pstTestPinsMri::MSG_ADC_INFO, name, pin, mv);
528 g_serialIO.
print(pstTestPinsMri::MSG_ADC_SHORT_TO_GND_WARN);
533 g_serialIO.
print(pstTestPinsMri::MSG_ADC_SHORT_TO_3V3_WARN);
556 bool _testI2cLineCheck(uint8_t pin,
const char *name,
const char *lineName)
const
558 g_serialIO.
sprintf(pstTestPinsMri::MSG_I2C_LINE_HDR, lineName, name, pin);
563 int idle = digitalRead(pin);
567 g_serialIO.
sprintf(pstTestPinsMri::MSG_I2C_PULLUP_PASS, lineName);
572 pinMode(pin, INPUT_PULLUP);
574 int nudged = digitalRead(pin);
578 g_serialIO.
sprintf(pstTestPinsMri::MSG_I2C_MISSING_PULLUP_FAIL, lineName);
583 g_serialIO.
sprintf(pstTestPinsMri::MSG_I2C_SHORT_TO_GROUND_FAIL, lineName);
Header-only class for receiving and buffering command packets over UART, Bluetooth,...
uint8_t digitalRead(uint8_t p)
Reads the specified pin.
void pinMode(uint8_t p, uint8_t d)
void pullUp(uint8_t p, uint8_t d)
Enables the pull-up resistor on the specified pin.
One-stop pin self-test utility with a single dispatcher entry point.
static void set_led(uint8_t pin, bool on)
Convenience: drive an indicator LED with active-LOW polarity.
static void init_led(uint8_t pin)
Initialize an indicator LED pin (OUTPUT, start OFF).
PstTestPins()
Default constructor (no configuration needed for ESP32).
bool testShorted(uint8_t pin, const char *label=nullptr, bool gentle=false) const
Run only the "shorted" heuristic on a pin.
@ I2C_SCL
I²C clock line (idle HIGH)
@ UART_RX
DF TX -> ESP32 RX (Input with gentle bias)
@ UART_TX
ESP32 TX -> DF RX (Output; idle HIGH)
@ Input
digital input only
@ PWM
PWM-capable output (basic toggle check here)
@ Button
momentary input (basic stuck check)
@ OpenDrain
OD output: drive LOW, release HIGH.
@ I2C_SDA
I²C data line (idle HIGH)
@ IO
general-purpose (can be in/out)
@ McpInput
NEW: probe an MCP23017 input pin (pull-up ON, read HIGH/LOW)
bool testMcpInput(Adafruit_MCP23017 *pMcp, uint8_t mcpPin, const char *name) const
Run input test on an MCP23017 pin.
bool testOpen(uint8_t pin, const char *label=nullptr, bool gentle=false) const
Run only the "open" heuristic on a pin.
bool testPin(uint8_t pin, Type type, const char *label=nullptr) const
Run the appropriate self-test(s) for a pin based on its Type.
void print(const char *msg)
Print a string to all active consoles.
void sprintf(const char *fmt,...)
printf-style logging to all active consoles (no newline).