feat(m5stack-core): header pins resolve, and PWM tones carry their real pitch

Two faults from the same audit. Every wire from the Core's M-Bus header
resolved to null: the kind does not start with 'esp32', so boardPinToNumber
fell through every branch and a part wired to the header never saw a signal,
with nothing anywhere saying why. A dedicated branch (like the Cardputer's)
maps the bare-number pads, sends 5V/GND/3V3/BAT to -1, and three new tests
pin it — the board had zero test coverage before.

And LEDC events now carry the carrier frequency. The engines have always
known it; LedcDuty just had no field for it, so a speaker listener could only
ever play a canned note — the Core's piano spent its life on 660 Hz. The duty
handler stashes it per pin in the PinManager (getPwmFreq), a side table
rather than a new callback parameter so the existing two- and three-arg PWM
listeners stay untouched.
This commit is contained in:
David Montero Crespo 2026-08-12 15:19:30 +02:00
parent ae70595239
commit cc3b67f724
2 changed files with 43 additions and 0 deletions

View File

@ -42,3 +42,28 @@ describe('boardPinToNumber — M5 Cardputer ADV header', () => {
expect(boardPinToNumber('cardputer-adv', '99')).toBeNull();
});
});
describe('m5stack-core header pins', () => {
// The Core's pads sat unmapped for months: the kind does not start with
// 'esp32', so it fell through every branch and each wire from the M-Bus
// header resolved to null — a part wired to the header never saw a signal,
// silently. These pin the dedicated branch.
const CORE_GPIO = ['21', '22', '23', '19', '18', '3', '1', '16', '17', '2', '5', '25', '26', '35', '36', '12', '13', '15', '0', '34'];
it('maps every M-Bus GPIO pad to its number', () => {
for (const name of CORE_GPIO) {
expect(boardPinToNumber('m5stack-core', name)).toBe(Number(name));
}
});
it('maps the power pads (including BAT) to -1', () => {
for (const name of ['5V', 'GND', '3V3', 'BAT']) {
expect(boardPinToNumber('m5stack-core', name)).toBe(-1);
}
});
it('rejects out-of-range and non-pins', () => {
expect(boardPinToNumber('m5stack-core', '40')).toBeNull(); // classic tops out at 39
expect(boardPinToNumber('m5stack-core', 'NOPE')).toBeNull();
});
});

View File

@ -361,6 +361,24 @@ export function boardPinToNumber(boardId: string, pinName: string): number | nul
return null;
}
// M5Stack Core: same bare-GPIO-number pads, classic ESP32 range. Without
// this branch the kind fell through every one below — the shared ESP32
// branch requires boardId.startsWith('esp32') — and every wire from the
// M-Bus header resolved to null: a part wired to the header never saw a
// signal, with nothing anywhere saying why. BAT joins the power names.
if (boardId === 'm5stack-core') {
if (
pinName.startsWith('GND') ||
pinName.startsWith('3V3') ||
pinName.startsWith('5V') ||
pinName === 'BAT'
)
return -1;
const num = parseInt(pinName, 10);
if (!isNaN(num) && num >= 0 && num <= 39) return num;
return null;
}
// ESP32 / ESP32-S3 / ESP32-C3 — GPIO numbers used directly
if (boardId === 'esp32' || boardId.startsWith('esp32')) {
// Power / GND pins (GND, GND.1, 3V3, 3V3.1, 5V, 5V.1, etc.)