From 64b3a99a278d62b68d9450d91693e6694eb76640 Mon Sep 17 00:00:00 2001 From: Michael B Reiser Date: Tue, 29 Sep 2026 15:39:26 -0400 Subject: [PATCH 1/2] =?UTF-8?q?fix(studio):=20Digital=20IO=201=20can't=20b?= =?UTF-8?q?e=20the=20trigger=20input=20=E2=80=94=20only=20Digital=20IO=202?= =?UTF-8?q?=20reaches=20EINT=20(#168)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only the "Digital IO 2 (5V)" BNC is wired to the panels' EINT net (U3 + J30 shunt); Digital IO 1 has no route, so `in_trigger` there gave a silently dead trigger. - parseRigIo: `in_trigger` on dio port 1 degrades to off with a warning naming Digital IO 2 (shown in the Console log at connect). - Studio Rig I/O menu: the Digital IO 1 `in_trigger` option stays disabled on every firmware, with the reason as its tooltip; capability gating no longer enables it. - Rig-io apply path: never sends SET_DIO_ROLE in_trigger to channel 1. - Tests: N12io-c2 (parser + static Studio checks). The controller-side refusal is reiserlab/LED-Display_G6_Firmware_Arena#45. Co-Authored-By: Claude Opus 5.5 --- arena_studio.html | 10 ++++++-- js/plugin-registry.js | 8 ++++++ tests/test-protocol-roundtrip-v3.js | 40 +++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/arena_studio.html b/arena_studio.html index 126d66e1..00275113 100644 --- a/arena_studio.html +++ b/arena_studio.html @@ -2782,7 +2782,7 @@

Import error

@@ -6938,7 +6938,8 @@

Import error

opt.title = on ? title : 'Needs io_ext firmware (0xC2 capability bit 5) — connect a controller running feat/dio-roles-ao-modes or later.'; }; - gate('cIoRoleDio1', 'in_trigger', 'Input role — on Digital IO 2 this is the EINT trigger route (J30); pulse-semantics bench validation pending.'); + // No gate for Digital IO 1 in_trigger: that BNC has no route to the panels' EINT net, so the + // option stays disabled on every firmware (#168). Only Digital IO 2 can be the trigger input. gate('cIoRoleDio2', 'in_trigger', 'Input role — the EINT trigger route to the panels (J30 shunt); pulse-semantics bench validation pending.'); gate('cIoRoleDio1', 'out_debug_framescan', 'Scope envelope: HIGH exactly while each frame\'s SPI transmission runs (bench-verified).'); gate('cIoRoleDio2', 'out_debug_framescan', 'Scope envelope: HIGH exactly while each frame\'s SPI transmission runs. NOTE: with the J30 shunt installed this also pulses the panels\' EINT net.'); @@ -6993,6 +6994,11 @@

Import error

const r = roleOf(d.port === 1 ? 'cIoRoleDio1' : 'cIoRoleDio2', d.role); const ch = d.port; // io: port == wire channel == board "Digital IO n (5V)" label if (r === 'off') continue; // off = DON'T TOUCH (keeps fw boot roles, e.g. port 2 in_trigger) + if (ch === 1 && r === 'in_trigger') { + // Digital IO 1 has no EINT route: the trigger would be silently dead (#168). + clog('rig io: Digital IO 1 cannot be the trigger input (only Digital IO 2 reaches the panels\' EINT) — not applied', 'warn'); + continue; + } if (ext) { // Explicit role first (SET_DIO_ROLE 0xAC), then the level for outputs. try { diff --git a/js/plugin-registry.js b/js/plugin-registry.js index 4001884e..50f75c81 100644 --- a/js/plugin-registry.js +++ b/js/plugin-registry.js @@ -1253,6 +1253,14 @@ function parseRigIo(rigData) { } var slot = result.dio[port - 1]; slot.role = _rigIoRole(entry.role, RIG_IO_ROLES.dio, 'dio port ' + port, result.warnings); + // Only "Digital IO 2 (5V)" is wired to the panels' EINT trigger net (U3 + J30 shunt). + // Digital IO 1 has no route, so in_trigger there would be a silently dead trigger (#168). + if (port === 1 && slot.role === 'in_trigger') { + result.warnings.push( + 'dio port 1 cannot be in_trigger: only "Digital IO 2 (5V)" reaches the panels\' trigger input (EINT); treated as off' + ); + slot.role = 'off'; + } // default is outputs-only; clamp anything truthy-numeric/boolean to 0|1. if (entry.default != null) slot.default = entry.default === true || Number(entry.default) === 1 ? 1 : 0; diff --git a/tests/test-protocol-roundtrip-v3.js b/tests/test-protocol-roundtrip-v3.js index 702cecab..c82b736a 100644 --- a/tests/test-protocol-roundtrip-v3.js +++ b/tests/test-protocol-roundtrip-v3.js @@ -3846,6 +3846,46 @@ console.log('\n--- Suite N12io: rig io: block (#135) ---'); bad.warnings.join(' | ') ); + // (c2) #168: Digital IO 1 has no route to the panels' EINT trigger net — in_trigger on + // port 1 degrades to off with a warning naming Digital IO 2; port 2 keeps it. + const trig = parseRigIo({ + io: { + dio: [ + { port: 1, role: 'in_trigger' }, + { port: 2, role: 'in_trigger' } + ] + } + }); + check('N12io-c2: port 1 in_trigger → off (no EINT route)', trig.dio[0].role, 'off'); + check('N12io-c2: port 2 in_trigger kept (the EINT route)', trig.dio[1].role, 'in_trigger'); + checkTrue( + 'N12io-c2: one warning, naming Digital IO 2', + trig.warnings.length === 1 && + /port 1 cannot be in_trigger/.test(trig.warnings[0]) && + /Digital IO 2/.test(trig.warnings[0]), + trig.warnings.join(' | ') + ); + // The Studio side: the DIO 1 option is disabled with the reason, never re-enabled by + // capability gating, and the apply path refuses to send it. + const studioHtml = fs.readFileSync(path.join(__dirname, '..', 'arena_studio.html'), 'utf8'); + checkTrue( + 'N12io-c2: Studio DIO 1 in_trigger option disabled with the EINT reason', + / + + @@ -6938,8 +6937,8 @@

Import error

opt.title = on ? title : 'Needs io_ext firmware (0xC2 capability bit 5) — connect a controller running feat/dio-roles-ao-modes or later.'; }; - // No gate for Digital IO 1 in_trigger: that BNC has no route to the panels' EINT net, so the - // option stays disabled on every firmware (#168). Only Digital IO 2 can be the trigger input. + // Digital IO 1 has no in_trigger option at all: that BNC has no route to the panels' EINT net + // (#168). Only Digital IO 2 can be the trigger input. gate('cIoRoleDio2', 'in_trigger', 'Input role — the EINT trigger route to the panels (J30 shunt); pulse-semantics bench validation pending.'); gate('cIoRoleDio1', 'out_debug_framescan', 'Scope envelope: HIGH exactly while each frame\'s SPI transmission runs (bench-verified).'); gate('cIoRoleDio2', 'out_debug_framescan', 'Scope envelope: HIGH exactly while each frame\'s SPI transmission runs. NOTE: with the J30 shunt installed this also pulses the panels\' EINT net.'); diff --git a/tests/test-protocol-roundtrip-v3.js b/tests/test-protocol-roundtrip-v3.js index c82b736a..5bc8f657 100644 --- a/tests/test-protocol-roundtrip-v3.js +++ b/tests/test-protocol-roundtrip-v3.js @@ -3865,15 +3865,22 @@ console.log('\n--- Suite N12io: rig io: block (#135) ---'); /Digital IO 2/.test(trig.warnings[0]), trig.warnings.join(' | ') ); - // The Studio side: the DIO 1 option is disabled with the reason, never re-enabled by - // capability gating, and the apply path refuses to send it. + // The Studio side: Digital IO 1 offers no in_trigger option at all (the reason is in its + // tooltip), capability gating never adds it back, and the apply path refuses to send it. const studioHtml = fs.readFileSync(path.join(__dirname, '..', 'arena_studio.html'), 'utf8'); + const dio1Select = (studioHtml.match(/