AB CIP UDT Template Object shape reader #131

Merged
dohertj2 merged 1 commits from abcip-udt-template-reader into v2 2026-04-19 21:23:35 -04:00
Owner

Closes the shape-reader half of task #179. CipTemplateObjectDecoder parses Read Template blob per Rockwell CIP Vol 1 (12-byte header + 8-byte member blocks + semicolon-delimited strings). IAbCipTemplateReader abstraction + LibplctagTemplateReader using @udt/{id} pseudo-tag. AbCipDriver.FetchUdtShapeAsync populates AbCipTemplateCache. 22 new tests, 211/211 passing. Whole-UDT read optimization still pending as a follow-up. Merges to v2.

Closes the shape-reader half of task #179. CipTemplateObjectDecoder parses Read Template blob per Rockwell CIP Vol 1 (12-byte header + 8-byte member blocks + semicolon-delimited strings). IAbCipTemplateReader abstraction + LibplctagTemplateReader using @udt/{id} pseudo-tag. AbCipDriver.FetchUdtShapeAsync populates AbCipTemplateCache. 22 new tests, 211/211 passing. Whole-UDT read optimization still pending as a follow-up. Merges to v2.
dohertj2 added 1 commit 2026-04-19 21:23:32 -04:00
AB CIP UDT Template Object shape reader. Closes the shape-reader half of task #179. CipTemplateObjectDecoder (pure-managed) parses the Read Template blob per Rockwell CIP Vol 1 + libplctag ab/cip.c handle_read_template_reply — 12-byte header (u16 member_count + u16 struct_handle + u32 instance_size + u32 member_def_size) followed by memberCount × 8-byte member blocks (u16 info with bit-15 struct flag + lower-12-bit type code matching the Symbol Object encoding, u16 array_size, u32 struct_offset) followed by semicolon-terminated strings (UDT name first, then one per member). ParseSemicolonTerminatedStrings handles the observed firmware variations — name;\0 vs name; delimiters, optional null/space padding after the semicolon, trailing-name-without-semicolon corner case. Struct-flag members decode as AbCipDataType.Structure; unknown atomic codes fall back to Structure so the shape remains valid even with unrecognised members. Zero member count + short buffer both return null; missing member names yield <member_N> placeholders. IAbCipTemplateReader + IAbCipTemplateReaderFactory abstraction — one call per template instance id returning the raw blob. LibplctagTemplateReader is the production implementation creating a libplctag Tag with name @udt/{templateId} + handing the buffer to the decoder. AbCipDriver ctor gains optional templateReaderFactory parameter (defaults to LibplctagTemplateReaderFactory) + new internal FetchUdtShapeAsync that — checks AbCipTemplateCache first, misses call the reader + decode + cache, template-read exceptions + decode failures return null so callers can fall back to declaration-driven fan-out without the whole discovery blowing up. OperationCanceledException rethrows for shutdown propagation. Unknown device host returns null without attempting a fetch. FlushOptionalCachesAsync empties the cache so a subsequent fetch re-reads. 16 new decoder tests — simple two-member UDT, struct-member flag → Structure, array member ArrayLength, 6-member mixed-type with correct offsets, unknown type code → Structure, zero member count → null, short buffer → null, missing member name → placeholder, ParseSemicolonTerminatedStrings theory across 5 shapes. 6 new AbCipFetchUdtShapeTests exercising the driver integration via reflection (method is internal) — happy-path decode + cache, different template ids get separate fetches, unknown device → null without reader creation, decode failure returns null + doesn't cache (next call retries), reader exception returns null, FlushOptionalCachesAsync clears the cache. Total AbCip unit tests now 211/211 passing (+19 from the @tags merge's 192); full solution builds 0 errors; other drivers untouched. Whole-UDT read optimization (single libplctag call returning the packed buffer + client-side member decode using the template offsets) is left as a follow-up — requires rethinking the per-tag read path + careful hardware validation; current per-member fan-out still works correctly, just with N round-trips instead of 1. ece530d133
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dohertj2 merged commit 5536e96b46 into v2 2026-04-19 21:23:35 -04:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dohertj2/lmxopcua#131