Fix bit-device read point count for optimized blocks - #19
Open
parthi2929 wants to merge 1 commit into
Open
parthi2929 wants to merge 1 commit into
parthi2929 wants to merge 1 commit into
Conversation
When several bit items (M/X/Y/etc) are close enough together, the read
optimizer merges them into a single block and grows the block's
byteLength to span the whole range. arrayLength and remainder, however,
continue to describe only the first item in the block.
Both MCAddrToBuffer1E and MCAddrToBuffer3E derived the SLMP "number of
device points" field from ceil((arrayLength + remainder) / 16), so a
merged block spanning several words still requested a single word. The
PLC replies correctly with the one word it was asked for, then
processMBPacket compares that against the block's byteLength and rejects
it with "Invalid Response Length - Expected N but got 2 bytes", marking
every item in the block bad quality.
Bit reads use word-unit subcommands, so byteLength/2 is the correct
point count. For an unoptimized item byteLength is already wordLength*2,
so single-item reads are unaffected; the optimizer also keeps byteLength
even. This mirrors what the non-bit branch of both functions already
does.
Minimal reproduction - two bit tags landing in different words:
conn.addItems(['M0', 'M20']);
conn.readAllItems(cb);
before: head=M0 points=1 -> "Invalid Response Length - Expected 4 but
got 2 bytes", M0 and M20 both BAD 255
after: head=M0 points=2 -> both items read, anythingBad === false
Co-Authored-By: Claude Opus 5 <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.
Problem
Reading more than one bit device (
M,X,Y, …) fails whenever the read optimizer merges those items into a single block that spans more than one 16-bit word. Every item in the affected block comes back with bad quality (255) and the console fills with:Single bit items, and groups that happen to fall inside one word, work fine — which makes this look intermittent and address-dependent rather than systematic.
Root cause
prepareReadPacket's optimizer merges nearby bit items into one block and grows that block'sbyteLengthto cover the whole span:https://github.com/plcpeople/mcprotocol/blob/master/mcprotocol.js#L631-L639
arrayLengthandremainder, though, keep describing only the first item in the block.Both address builders derived the SLMP number of device points field from
Math.ceil((arrayLength + remainder) / 16):MCAddrToBuffer1E— L1883MCAddrToBuffer3E— L1989 (ASCII), L2003 (binary)For a merged block that still evaluates to 1 word, so the request under-asks. The PLC answers correctly with the single word it was asked for, and then
processMBPacketcompares the reply against the block'sbyteLengthand rejects it, failing every item in the block:https://github.com/plcpeople/mcprotocol/blob/master/mcprotocol.js#L1269-L1304
The PLC is behaving correctly throughout; the request itself is malformed.
Minimal reproduction
Two bit tags, 21 bits apart, so they merge into one block spanning two words:
The stand-in server answers with exactly the number of words the library asks for, as a real PLC does.
Before:
After:
The fix
Bit reads already use the word-unit subcommand, so the point count is simply
byteLength / 2.This is the same expression the non-bit branch of both functions uses, a few lines below each changed line — and the
// doesn't work with optimized blocks where array length isn't rightcomment sitting immediately after each site suggests the word path was corrected for exactly this reason while the bit path was missed.No behaviour change for unoptimized items:
byteLengthis set towordLength * 2instringToMCAddr, so a lone bit item still requests one word. The optimizer also forcesbyteLengtheven, sobyteLength / 2is always an integer.Writes are untouched — only the
bitNative && !isWritingbranches change.Verified
Against
master(f174d5b), with a stand-in PLC as above, and additionally on real hardware: a Mitsubishi FX5 over SLMP, where a project with 78 bit tags went from 3 readable to all 78 readable, with theInvalid Response Lengthmessages and the resulting bad-quality reads gone entirely.Reported downstream in FUXA, which pins
mcprotocol@0.1.2for its MELSEC driver: frangoteam/FUXA#2512