fix(catalog,codec): honour per-instance compound TIPO overrides; add ENUM_WORD and INT#18
Merged
Merged
Conversation
…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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #6, #9, #10. The design write-up lives in the pinned comment on #6; this is the implementation.
What changed
Catalog parser —
pkg/catalog/menu.go:decodeDataChildrenno longer skips nested<DATA>elements. Each one populatesData.CompoundOverrides[childName] = {Tipo: childTipo}.resolveTypedefswalks the overrides too soENUM_RELE/ENUM_LED/ENUM_INGaliases stay resolved even inside overrides.Codec —
EncodeCompoundandDecodeCompoundgain an overrides argument. A privateapplyOverridereturns a per-iterationClassVarwith the effectiveTIPO; everything else is unchanged.overrides == nilis a no-op so callers that don't carry overrides keep working unmodified.Session —
pkg/session/{set,read}.gopassd.CompoundOverridesthrough 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=5split intoINT + 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 afterCompoundOverridesare applied (the cases this fix addresses), 0 mismatches remain. Same result on the default-locale sweep overSIF-5600/SIF_8EVafter the INT addition.Unit tests in
pkg/codec/compound_test.gocover the override path with a synthesised CLASS, the ENUM_WORD width, and the INT signed-round-trip.pkg/catalog/menu_test.goasserts the parser populatesCompoundOverridesand that non-compound DATA stay untouched.pkg/session/set_test.gocovers 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.Fixture —
testdata/us/TEST-VB0-agains aSOGLIA_Tclass plus aTEST_SOGLIAinstance 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_INDdecodes the compound to{Stato=ON, Intervento=47040, IdxMisura=Umax …, Tipo=95200, KRilascio=1, Rilascio=470, TmInibizione=0, TmRitRicaduta=0}.Intervento=47040matches thePickup value=0.42 UnThyVisor 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