Fix decoding of multi-element register payloads - #44
Merged
Conversation
decode now sizes the payload from payload_class rather than from the register length, so a register whose payload spans several elements no longer rejects its own frames. Only an array register declares a length, so this reached every struct, string and mask register, including DeviceName. An array register declaring length in its class body now sizes its payload, where before only the call form did, so it would read the first element and discard the rest. A declared length of 1 is now distinct from an absent one, so such a register emits a one-element array rather than a scalar. Closes #36
length is no longer a member of every register. It moves to the array register metaclass, so an array register reports its element count and every other kind carries no length at all.
glopesdev
force-pushed
the
fix-register-length
branch
from
August 24, 2026 18:36
6205e9d to
a55a77b
Compare
bruno-f-cruz
requested changes
Aug 24, 2026
bruno-f-cruz
left a comment
Member
There was a problem hiding this comment.
One small clarification.
ConverterContext.length is now the effective element count and never zero, so span is a plain multiply and no emitted payload or converter changes.
bruno-f-cruz
approved these changes
Aug 24, 2026
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.
HarpMessage.decodesized the payload from the registerlengthwhileRegisterBase.parsesized it frompayload_class. Only array registers declare alength, so for every other kind the first calculation assumed a single element and rejected any longer frame.Device.readandDevice.writeboth end indecode, so this broke every register whose payload spans more than one element,DeviceNameon every Harp device included.decodenow readspayload_class.payload_dtype.itemsize, the same quantityparseuses, so there is one derivation and the two cannot disagree.PayloadDecoderdeclarespayload_classin place oflength, since every register has a payload class and only an array register has a length.What a declared length does
Two further defects surfaced in the same area, neither of them filed.
An array register can be declared two ways, by calling a base with an address and a length, or by subclassing with both in the class body. Only the first sized the payload, so the second would inherit a one-element payload and read the first element while discarding the rest.
device.olfactometeranddevice.soundcardboth carry registers in that shape. Sizing moved into the metaclass__init__, which runs for either form, and re-declaring a length on a subclass now raises rather than nesting one sub-array inside another.The schema model defaulted
lengthto 1, so an absent length and a declaredlength: 1arrived as the same value and both emitted a scalar. Both model fields now default toNonewith a minimum of 1, and the emitter branches on absence, so a declared 1 emits a one-element array. Alength: 0is rejected for a register and for a payload member, which the generator reads as absent.RegisterBase.lengthkeeps its type and its meaning, and no generated output changes. The emitter was checked against generator output for a schema covering an absent length, a declared 1, a declared 3 and struct payloads at both counts, comparing base class, payload type, length, dtype, field names and address, and decoding a frame built by one path through the other.Where length lives
RegisterBaseno longer declareslength. It moves to the array register metaclass, so an array register reports its element count and every other kind carries none.This follows from the
decodechange above. Once the payload class is the only thing that decides an extent, alengthon a scalar or struct register is alwaysNonewhile the payload spans several elements, which invites exactly the mistake this pull request fixes.Closes #36