@@ -14,6 +14,8 @@ internal sealed class LibplctagTagRuntime : IAbCipTagRuntime
|
||||
{
|
||||
private readonly Tag _tag;
|
||||
private readonly int _connectionSize;
|
||||
private readonly AddressingMode _addressingMode;
|
||||
private readonly uint? _logicalInstanceId;
|
||||
|
||||
public LibplctagTagRuntime(AbCipTagCreateParams p)
|
||||
{
|
||||
@@ -38,6 +40,8 @@ internal sealed class LibplctagTagRuntime : IAbCipTagRuntime
|
||||
if (p.ElementCount is int n && n > 0)
|
||||
_tag.ElementCount = n;
|
||||
_connectionSize = p.ConnectionSize;
|
||||
_addressingMode = p.AddressingMode;
|
||||
_logicalInstanceId = p.LogicalInstanceId;
|
||||
}
|
||||
|
||||
public async Task InitializeAsync(CancellationToken cancellationToken)
|
||||
@@ -53,6 +57,16 @@ internal sealed class LibplctagTagRuntime : IAbCipTagRuntime
|
||||
// to the wrapper default. Failures (older / patched wrappers without the internal API)
|
||||
// are intentionally swallowed so the driver keeps initialising.
|
||||
TrySetConnectionSize(_tag, _connectionSize);
|
||||
|
||||
// PR abcip-3.2 — propagate the addressing mode + (when known) the resolved Symbol
|
||||
// Object instance ID. Same reflection-fallback shape as ConnectionSize: the libplctag
|
||||
// .NET wrapper (1.5.x) doesn't expose a public knob for instance-ID addressing, so
|
||||
// we forward the relevant attribute string through NativeTagWrapper.SetAttributeString.
|
||||
// Logical mode lights up only when the driver has populated LogicalInstanceId via the
|
||||
// one-time @tags walk; first reads on a Logical device + every Symbolic-mode read take
|
||||
// the libplctag default ASCII-symbolic path.
|
||||
if (_addressingMode == AddressingMode.Logical)
|
||||
TrySetLogicalAddressing(_tag, _logicalInstanceId);
|
||||
}
|
||||
|
||||
public Task ReadAsync(CancellationToken cancellationToken) => _tag.ReadAsync(cancellationToken);
|
||||
@@ -86,6 +100,47 @@ internal sealed class LibplctagTagRuntime : IAbCipTagRuntime
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PR abcip-3.2 — best-effort propagation of CIP logical-segment / instance-ID
|
||||
/// addressing to libplctag native. Two attributes are forwarded:
|
||||
/// <list type="bullet">
|
||||
/// <item><c>use_connected_msg=1</c> — instance-ID addressing only works over a
|
||||
/// connected CIP session; switch the tag to use Forward Open + Class3 messaging.</item>
|
||||
/// <item><c>cip_addr=0x6B,N</c> — replace the ASCII Symbol Object lookup with a
|
||||
/// direct logical segment reference, where <c>N</c> is the resolved instance ID
|
||||
/// from the driver's one-time <c>@tags</c> walk.</item>
|
||||
/// </list>
|
||||
/// Same reflection-via-<c>NativeTagWrapper.SetAttributeString</c> shape as
|
||||
/// <see cref="TrySetConnectionSize"/> — the 1.5.x .NET wrapper does not expose a
|
||||
/// public knob, so we degrade gracefully when the internal API is not present.
|
||||
/// </summary>
|
||||
private static void TrySetLogicalAddressing(Tag tag, uint? logicalInstanceId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var wrapperField = typeof(Tag).GetField("_tag", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
var wrapper = wrapperField?.GetValue(tag);
|
||||
if (wrapper is null) return;
|
||||
var setStr = wrapper.GetType().GetMethod(
|
||||
"SetAttributeString",
|
||||
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
|
||||
binder: null,
|
||||
types: [typeof(string), typeof(string)],
|
||||
modifiers: null);
|
||||
if (setStr is null) return;
|
||||
setStr.Invoke(wrapper, ["use_connected_msg", "1"]);
|
||||
if (logicalInstanceId is uint id)
|
||||
setStr.Invoke(wrapper, ["cip_addr", $"0x6B,{id}"]);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Wrapper internals not present / shifted — fall back to symbolic addressing on
|
||||
// the wire. Driver-level logical-mode bookkeeping (the @tags map) is still useful
|
||||
// because future wrapper releases may expose this attribute publicly + the
|
||||
// reflection lights up cleanly then.
|
||||
}
|
||||
}
|
||||
|
||||
public int GetStatus() => (int)_tag.GetStatus();
|
||||
|
||||
public object? DecodeValue(AbCipDataType type, int? bitIndex) => DecodeValueAt(type, 0, bitIndex);
|
||||
|
||||
Reference in New Issue
Block a user