fix(interconnect): classify Arduino Mega UART/I2C function-label pins
Follow-up audit after the ESP32 fix: classifyPin() was run for every board against the protocol pin labels its element actually exposes. One real gap remained -- Arduino Mega. Its dedicated SDA/SCL pins are only labelled (not numbered), so I2C links drawn on them came back 'digital' and never bridged. Map every Mega function label (TX/RX, TX0-3/RX0-3, SDA/SCL) to its pin number. Audit result for the rest (added as board-protocols-audit.test.ts): - Arduino Uno/Nano, Pico/Pico-W, STM32 Blue Pill: already OK. - ESP32 / ESP32-C3: fixed earlier (esp32-uart-pin-classify). - Raspberry Pi 3/4/5: OK -- the element labels pins by physical number (1..40) which normalize to BCM, so no function-label gap exists there.
This commit is contained in:
parent
d69897409a
commit
fddc03aa60
|
|
@ -0,0 +1,73 @@
|
||||||
|
/**
|
||||||
|
* Cross-board audit: a wire drawn on a board's protocol pins must classify as
|
||||||
|
* UART/I2C/SPI (not raw digital) so the Interconnect installs the byte-level
|
||||||
|
* bridge. Tests every supported board against the pin labels its element
|
||||||
|
* actually exposes.
|
||||||
|
*
|
||||||
|
* Boards expose pins differently:
|
||||||
|
* - Arduino Uno/Nano: numbers + TX/RX/SDA/SCL labels.
|
||||||
|
* - Arduino Mega: numbers for UART, dedicated SDA/SCL labels for I2C.
|
||||||
|
* - ESP32 / ESP32-C3: TX0/RX0/TX2/RX2 labels + GPIO numbers.
|
||||||
|
* - Pico/Pico-W: GPn labels.
|
||||||
|
* - STM32 Blue Pill: PAn/PBn port labels.
|
||||||
|
* - Raspberry Pi 3/4/5: PHYSICAL pin numbers (1..40) -> BCM.
|
||||||
|
*/
|
||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
|
import { classifyPin } from '../utils/boardProtocols';
|
||||||
|
|
||||||
|
const notDigital = (bk: string, pin: string) => {
|
||||||
|
const r = classifyPin(bk, pin);
|
||||||
|
expect(r.kind, `${bk} pin ${pin} classified as ${r.kind}`).not.toBe('digital');
|
||||||
|
return r;
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('board protocol-pin classification (multi-board interconnect)', () => {
|
||||||
|
it('Arduino Uno/Nano: TX/RX/SDA/SCL', () => {
|
||||||
|
for (const bk of ['arduino-uno', 'arduino-nano']) {
|
||||||
|
expect(classifyPin(bk, 'TX')).toEqual({ kind: 'uart-tx', uart: 0 });
|
||||||
|
expect(classifyPin(bk, 'RX')).toEqual({ kind: 'uart-rx', uart: 0 });
|
||||||
|
expect(classifyPin(bk, 'SDA')).toEqual({ kind: 'i2c-sda', bus: 0 });
|
||||||
|
expect(classifyPin(bk, 'SCL')).toEqual({ kind: 'i2c-scl', bus: 0 });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Arduino Mega: 4 UARTs by label + dedicated SDA/SCL', () => {
|
||||||
|
expect(classifyPin('arduino-mega', 'TX1')).toEqual({ kind: 'uart-tx', uart: 1 });
|
||||||
|
expect(classifyPin('arduino-mega', 'RX1')).toEqual({ kind: 'uart-rx', uart: 1 });
|
||||||
|
expect(classifyPin('arduino-mega', 'TX2')).toEqual({ kind: 'uart-tx', uart: 2 });
|
||||||
|
expect(classifyPin('arduino-mega', 'TX3')).toEqual({ kind: 'uart-tx', uart: 3 });
|
||||||
|
expect(classifyPin('arduino-mega', 'SDA')).toEqual({ kind: 'i2c-sda', bus: 0 });
|
||||||
|
expect(classifyPin('arduino-mega', 'SCL')).toEqual({ kind: 'i2c-scl', bus: 0 });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ESP32 variants + C3: UART labels', () => {
|
||||||
|
for (const bk of ['esp32', 'esp32-devkit-c-v4', 'esp32-cam', 'esp32-s3']) {
|
||||||
|
notDigital(bk, 'TX0');
|
||||||
|
notDigital(bk, 'RX0');
|
||||||
|
notDigital(bk, 'TX2');
|
||||||
|
notDigital(bk, 'RX2');
|
||||||
|
}
|
||||||
|
expect(classifyPin('esp32-c3', 'TX')).toEqual({ kind: 'uart-tx', uart: 0 });
|
||||||
|
expect(classifyPin('esp32-c3', 'SDA')).toEqual({ kind: 'i2c-sda', bus: 0 });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Pico/Pico-W: GPn labels', () => {
|
||||||
|
for (const bk of ['raspberry-pi-pico', 'pi-pico-w']) {
|
||||||
|
notDigital(bk, 'GP0');
|
||||||
|
notDigital(bk, 'GP1');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('STM32 Blue Pill: PAn USART labels', () => {
|
||||||
|
expect(classifyPin('stm32-bluepill', 'PA9')).toEqual({ kind: 'uart-tx', uart: 0 });
|
||||||
|
expect(classifyPin('stm32-bluepill', 'PA10')).toEqual({ kind: 'uart-rx', uart: 0 });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Raspberry Pi 3: physical pin numbers map to BCM protocol roles', () => {
|
||||||
|
// Physical 8/10 = BCM14/15 = UART0; physical 3/5 = BCM2/3 = I2C1.
|
||||||
|
expect(classifyPin('raspberry-pi-3', '8')).toEqual({ kind: 'uart-tx', uart: 0 });
|
||||||
|
expect(classifyPin('raspberry-pi-3', '10')).toEqual({ kind: 'uart-rx', uart: 0 });
|
||||||
|
expect(classifyPin('raspberry-pi-3', '3')).toEqual({ kind: 'i2c-sda', bus: 1 });
|
||||||
|
expect(classifyPin('raspberry-pi-3', '5')).toEqual({ kind: 'i2c-scl', bus: 1 });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -236,6 +236,20 @@ function normalizePinName(boardKind: string, pinName: string): string | null {
|
||||||
// wemos-lolin32-lite — works, mirroring tableFor(). esp32-c3 has its own pins.
|
// wemos-lolin32-lite — works, mirroring tableFor(). esp32-c3 has its own pins.
|
||||||
const isEsp32 = boardKind.startsWith('esp32');
|
const isEsp32 = boardKind.startsWith('esp32');
|
||||||
const isEsp32C3 = boardKind.startsWith('esp32-c3');
|
const isEsp32C3 = boardKind.startsWith('esp32-c3');
|
||||||
|
|
||||||
|
// Arduino Mega exposes 4 hardware UARTs + I2C by silkscreen label. Its UART
|
||||||
|
// pins are also numbered (0/1, 18/19, 16/17, 14/15) and classify on those,
|
||||||
|
// but the dedicated SDA/SCL pins are ONLY labelled, so I2C links drawn on
|
||||||
|
// them never classified. Map every Mega function label here.
|
||||||
|
if (boardKind === 'arduino-mega') {
|
||||||
|
const mega: Record<string, string> = {
|
||||||
|
TX: '1', RX: '0', TX0: '1', RX0: '0',
|
||||||
|
TX1: '18', RX1: '19', TX2: '16', RX2: '17', TX3: '14', RX3: '15',
|
||||||
|
SDA: '20', SCL: '21',
|
||||||
|
};
|
||||||
|
if (mega[trimmed]) return mega[trimmed];
|
||||||
|
}
|
||||||
|
|
||||||
if (trimmed === 'TX' || trimmed === 'TX0' || trimmed === 'TXD' || trimmed === 'TXD0') {
|
if (trimmed === 'TX' || trimmed === 'TX0' || trimmed === 'TXD' || trimmed === 'TXD0') {
|
||||||
if (boardKind === 'arduino-uno' || boardKind === 'arduino-nano') return '1';
|
if (boardKind === 'arduino-uno' || boardKind === 'arduino-nano') return '1';
|
||||||
if (boardKind === 'raspberry-pi-pico' || boardKind === 'pi-pico-w') return '0';
|
if (boardKind === 'raspberry-pi-pico' || boardKind === 'pi-pico-w') return '0';
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue