Skip to content

feat(examples): resolve M-area Byte/Word/DWord in browse_tags.py via symbolic READ#768

Open
tommasofaedo wants to merge 1 commit into
gijzelaerr:masterfrom
tommasofaedo:feat/browse-m-type-read
Open

feat(examples): resolve M-area Byte/Word/DWord in browse_tags.py via symbolic READ#768
tommasofaedo wants to merge 1 commit into
gijzelaerr:masterfrom
tommasofaedo:feat/browse-m-type-read

Conversation

@tommasofaedo

Copy link
Copy Markdown
Contributor

What

Follow-up to #756 / #767. Teaches examples/browse_tags.py to resolve the SIMATIC data type (and thus %MB/%MW/%MD address) of M-area tags, which the EXPLORE symbol blob cannot express.

Why

The EXPLORE symbol blob does not carry the data type of an M tag. The DataType attribute decodes to a constant — a back-reference to the same preset-dictionary position for a Byte, a Word and a DWord tag alike. I verified this with an oracle (DICT_ZERO/ONES/A/B) on tags of known type: all three reference dict[0x7b96]="Bool". So %MB/%MW/%MD are indistinguishable from the blob, and those tags previously printed LogicalAddress='?'.

How

A symbolic READ recovers the type. Reading an M tag by its LID (which equals the XML ID attribute) returns the value as a fixed-width raw block whose width is the declared type size:

width type address
1 byte Byte %MB
2 byte Word %MW
4 byte DWord %MD

_refine_m_widths() does this for every non-Bool M tag (Bool tags are already bit-addressed by EXPLORE and left untouched). It reuses a fresh connection per read, since the PLC resets the TCP session after the first symbolic operation.

Safety guard: if a tag's ID has any unmapped digit ('?'), the LID is uncertain and the refinement is skipped — better a '?' than a confident wrong type (a wrong LID would read a different object and could return a plausible-but-wrong width).

Also included:

  • Element-bounded ByteOffset extraction with two fallbacks, so the offset value is still recovered when the ByteOffset= label or the element close falls in unmapped FDICT positions.
  • Four FDICT positions for two-digit IDs (dict[0x7d20..21]='3\"', dict[0x7ddb..dc]='4\"'; previously 0).

Verification

Verified live on an S7-1200 FW V4.1 over TLS with controlled tags of known type/value:

mtag_byte  Byte*   %MB100   100   (READ -> 0x12,       1 byte)
mtag_word  Word*   %MW102   102   (READ -> 0x1234,     2 bytes)
mtag_dwrd  DWord*  %MD104   104   (READ -> 0x12345678, 4 bytes)
merker_1   Bool    %M0.2      0   (EXPLORE)
mtag_bool  Bool    %M108.0  108   (EXPLORE)

Values are exact; the DWord returns 4 raw bytes (not VLQ-compressed), confirming the width is the declared type size, not a value-minimised width. No regression on I/Q (input_1=%I0.0, output_1=%Q0.1).

Notes / honesty

  • Still example-only; no library code touched. pre-commit (ruff-format + ruff-check, v0.14.10) clean.
  • As noted on fix: browse() and list_datablocks() for V3 multi-frame EXPLORE (S7-1200 FW V4.5) #753, I no longer have the FW V4.5 "G1" unit; this was validated on the FW V4.1 "G2" over TLS. The technique is transport-agnostic and should close the 6 M-area gaps on the G1 reference project as well (33/40 → 39/40), but I could not re-verify on that hardware.
  • Tag names for these controlled tags still show a garbled suffix (e.g. mtag_wrue): those suffix bytes alias onto the preset-dict True token, so they can't be reconstructed without the full real dictionary. Type and address — what this PR is about — are exact.

🤖 Generated with Claude Code

…bolic READ

The EXPLORE symbol blob cannot carry the SIMATIC data type of an M tag: the
DataType attribute is a constant back-reference in the compressed stream —
identical for a Byte, a Word and a DWord tag (verified with an oracle on tags
of known type). So %MB/%MW/%MD could not be distinguished from the blob and
those tags previously showed LogicalAddress='?'.

A symbolic READ recovers it: reading an M tag by its LID (= the XML ID
attribute) returns the value as a fixed-width raw block whose width equals the
declared type size — 1 byte %MB, 2 %MW, 4 %MD. _refine_m_widths() applies this
to every non-Bool M tag (Bool tags stay bit-addressed from EXPLORE).

Safety: tags whose ID has an unmapped digit ('?') are skipped, so a wrong LID
can never yield a confident wrong type.

Also: element-bounded ByteOffset extraction (two fallbacks for garbled labels/
closings) and four FDICT positions for two-digit IDs.

Verified live on an S7-1200 FW V4.1 over TLS with controlled tags:
Byte=0x12->1B (%MB100), Word=0x1234->2B (%MW102), DWord=0x12345678->4B (%MD104);
no regression on I/Q (input_1=%I0.0, output_1=%Q0.1).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant