using System.Collections.Concurrent; namespace ZB.MOM.WW.OtOpcUa.Driver.AbCip; /// /// Cache of UDT shape descriptors keyed by (deviceHostAddress, templateInstanceId). /// Populated on demand during discovery + whole-UDT reads; flushed via /// and on device /// ReinitializeAsync. /// /// /// Template shape read (CIP Template Object class 0x6C, GetAttributeList + /// Read Template) lands with PR 6. This class ships the cache surface so PR 6 can /// drop the decoder in without reshaping any caller code. /// public sealed class AbCipTemplateCache { private readonly ConcurrentDictionary<(string device, uint instanceId), AbCipUdtShape> _shapes = new(); /// /// Retrieve a cached UDT shape, or null if not yet read. /// public AbCipUdtShape? TryGet(string deviceHostAddress, uint templateInstanceId) => _shapes.TryGetValue((deviceHostAddress, templateInstanceId), out var shape) ? shape : null; /// Store a freshly-decoded UDT shape. public void Put(string deviceHostAddress, uint templateInstanceId, AbCipUdtShape shape) => _shapes[(deviceHostAddress, templateInstanceId)] = shape; /// Drop every cached shape — called on . public void Clear() => _shapes.Clear(); /// Count of cached shapes — exposed for diagnostics + tests. public int Count => _shapes.Count; } /// /// Decoded shape of one Logix UDT — member list + each member's offset + type. Populated /// by PR 6's Template Object reader. At PR 5 time this is the cache's value type only; /// no reader writes to it yet. /// /// UDT name as reported by the Template Object. /// Bytes the UDT occupies in a whole-UDT read buffer. /// Ordered list of members, each with its byte offset + type. public sealed record AbCipUdtShape( string TypeName, int TotalSize, IReadOnlyList Members); /// One member of a Logix UDT. public sealed record AbCipUdtMember( string Name, int Offset, AbCipDataType DataType, int ArrayLength);