diff --git a/frontend/src/__tests__/board-pin-mapping.test.ts b/frontend/src/__tests__/board-pin-mapping.test.ts index 58a10268..d3ad2595 100644 --- a/frontend/src/__tests__/board-pin-mapping.test.ts +++ b/frontend/src/__tests__/board-pin-mapping.test.ts @@ -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(); + }); +}); diff --git a/frontend/src/utils/boardPinMapping.ts b/frontend/src/utils/boardPinMapping.ts index 12a0d06c..b3d836da 100644 --- a/frontend/src/utils/boardPinMapping.ts +++ b/frontend/src/utils/boardPinMapping.ts @@ -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.)