Skip to content

fix(catalog,codec): honour per-instance compound TIPO overrides; add ENUM_WORD and INT#18

Merged
ale-rinaldi merged 1 commit into
mainfrom
fix/issue-6-compound-tipo-overrides
May 15, 2026
Merged

fix(catalog,codec): honour per-instance compound TIPO overrides; add ENUM_WORD and INT#18
ale-rinaldi merged 1 commit into
mainfrom
fix/issue-6-compound-tipo-overrides

Conversation

@ale-rinaldi

Copy link
Copy Markdown
Contributor

Closes #6, #9, #10. The design write-up lives in the pinned comment on #6; this is the implementation.

What changed

Catalog parserpkg/catalog/menu.go:decodeDataChildren no longer skips nested <DATA> elements. Each one populates Data.CompoundOverrides[childName] = {Tipo: childTipo}. resolveTypedefs walks the overrides too so ENUM_RELE/ENUM_LED/ENUM_ING aliases stay resolved even inside overrides.

CodecEncodeCompound and DecodeCompound gain an overrides argument. A private applyOverride returns a per-iteration ClassVar with the effective TIPO; everything else is unchanged. overrides == nil is a no-op so callers that don't carry overrides keep working unmodified.

Sessionpkg/session/{set,read}.go pass d.CompoundOverrides through to the codec when they encounter a compound DATA.

ENUM_WORD (closes #9) — added to every ENUM-family switch as a 1-reg sibling of ENUM/ENUM_BYTE. Used by SMEI templates for IdxMisura; without it, the affected SOGLIAs had a 1-reg gap that the cross-catalog audit kept reporting.

INT (closes #10) — added as a WORD synonym (signed 16-bit). The width was confirmed empirically against SIF5600.IdentificationResponse (dim=5 split into INT + LONG + INT + INT → INT must be 1 reg). The legacy SIF/SVF families use it; modern families do not.

Verification

Cross-catalog audit (/tmp/verify-overrides.go) over six representative templates from the NV10P / NV11B / NA10 / PROX / SMEI / XMR families: 9,816 compound DATA instances scanned, 8,929 already balanced at the CLASS level, 887 balance only after CompoundOverrides are applied (the cases this fix addresses), 0 mismatches remain. Same result on the default-locale sweep over SIF-5600 / SIF_8EV after the INT addition.

Unit tests in pkg/codec/compound_test.go cover the override path with a synthesised CLASS, the ENUM_WORD width, and the INT signed-round-trip. pkg/catalog/menu_test.go asserts the parser populates CompoundOverrides and that non-compound DATA stay untouched. pkg/session/set_test.go covers the end-to-end Set with a compound + overrides through the fake transport — emitting a 3-reg FC16 instead of the pre-fix 2-reg one.

Fixturetestdata/us/TEST-VB0-a gains a SOGLIA_T class plus a TEST_SOGLIA instance whose nested <DATA> children carry a TIPO override mirroring the real NV10P SOGLIA shape in miniature.

Live verification on an NV10P-EX0-u via the recording proxy: mythy read a_F27S1_S_IND decodes the compound to {Stato=ON, Intervento=47040, IdxMisura=Umax …, Tipo=95200, KRilascio=1, Rilascio=470, TmInibizione=0, TmRitRicaduta=0}. Intervento=47040 matches the Pickup value=0.42 Un ThyVisor reported (47040 = 0.42 × 112000). Pre-fix this would have been Raw bytes (the codec couldn't even map a width to the catalog VAR list) or scrambled values shifted by 2 positions.

🤖 Generated with Claude Code

…ENUM_WORD and INT

mythy used to compute compound-field layout from the <CLASS> alone.
For a third of currently-deployed templates that's enough; for the
rest, the per-instance <DATA TIPO="<class>"> carries nested <DATA
NAME="..." TIPO="..."> children that override the CLASS VAR TIPO with
a wider primitive. The clearest example is SOGLIA on NV10P: the CLASS
declares Stato and Tipo as ENUM (1 reg each), but every instance
overrides them to ENUM_LONG (2 reg each), bringing the actual layout
to 14 registers — matching the message dim. Without honouring the
override, mythy was encoding 12 registers, leaving Stato and Tipo
correct but shifting every subsequent sub-field by 2 positions on the
wire. ThyVisor wrote ~7 fields per SOGLIA into wrong device slots and
left the device's "hidden" registers — that actually weren't hidden,
just under-sized in the catalog — overwritten with arbitrary halves
of the user payload.

Parser: pkg/catalog/menu.go's decodeDataChildren stops skipping nested
<DATA> elements. Each one populates Data.CompoundOverrides[name] with
the override's TIPO. resolveTypedefs walks the overrides too so
ENUM_RELE/LED/ING resolution stays consistent.

Codec: pkg/codec/compound.go's EncodeCompound / DecodeCompound take an
overrides argument. applyOverride returns a per-iteration ClassVar
with the effective TIPO; the rest of the code path is unchanged. Plain
class lookups (no overrides) keep working — overrides=nil is a no-op.

Session: pkg/session/{set,read}.go pass d.CompoundOverrides through.

While auditing the result, two related TIPO names were still
unhandled and broke entire families:

  * ENUM_WORD (issue #9) — used by SMEI templates for IdxMisura,
    behaves identically to ENUM/ENUM_BYTE at 1 reg. Added to every
    ENUM-family switch.
  * INT (issue #10) — used by legacy SIF/SVF templates. Confirmed as
    a 16-bit signed integer by reading SIF5600.IdentificationResponse
    (dim=5 split into INT + LONG + INT + INT → INT must be 1 reg).
    Treated as a WORD synonym.

Verification across 9816 compound DATA instances spanning NV10P, NV11B,
NA10, PROX, SMEI, XMR families: 91% were already balanced at the
CLASS level, 9% balance only after the overrides are applied (the
ones this fix addresses), 0 mismatches remain. The default-locale
sweep over legacy SIF5600/SVF closes the INT gap with the same
result. Live read of a_F27S1_S_IND on a real NV10P returns the
decoded compound matching ThyVisor's display down to the byte.

Closes #6
Closes #9
Closes #10

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ale-rinaldi ale-rinaldi merged commit a799ad8 into main May 15, 2026
2 checks passed
@ale-rinaldi ale-rinaldi deleted the fix/issue-6-compound-tipo-overrides branch May 15, 2026 11:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant