feat(twincat): resolve equipment-tag refs (read + write) via EquipmentTagRefResolver

This commit is contained in:
Joseph Doherty
2026-06-13 11:24:12 -04:00
parent e2ea720c08
commit 5ebf541f54
3 changed files with 144 additions and 3 deletions
@@ -0,0 +1,49 @@
using System.Text.Json;
namespace ZB.MOM.WW.OtOpcUa.Driver.TwinCAT;
/// <summary>Parses an equipment tag's <c>TagConfig</c> JSON (the shape authored by the AdminUI
/// <c>TwinCATTagConfigModel</c>) into a transient <see cref="TwinCATTagDefinition"/> whose
/// <see cref="TwinCATTagDefinition.Name"/> equals the reference string itself, so a value the
/// driver publishes back keys the runtime's forward router correctly.</summary>
public static class TwinCATEquipmentTagParser
{
/// <summary>Attempts to parse an equipment-tag reference into a transient definition.</summary>
/// <param name="reference">The equipment tag's TagConfig JSON (also used as the def identity).</param>
/// <param name="def">The transient definition when parsing succeeds.</param>
/// <returns><see langword="true"/> when <paramref name="reference"/> is a TwinCAT symbol object.</returns>
public static bool TryParse(string reference, out TwinCATTagDefinition def)
{
def = null!;
// Authored tag names never start with '{' (AdminUI name validation), so a leading brace marks an equipment-tag TagConfig blob.
if (string.IsNullOrWhiteSpace(reference) || reference[0] != '{') return false;
try
{
using var doc = JsonDocument.Parse(reference);
var root = doc.RootElement;
if (root.ValueKind != JsonValueKind.Object
|| !root.TryGetProperty("symbolPath", out var symbol)
|| symbol.ValueKind != JsonValueKind.String)
return false;
var symbolPath = symbol.GetString();
if (string.IsNullOrWhiteSpace(symbolPath)) return false;
var deviceHostAddress = ReadString(root, "deviceHostAddress");
var dataType = ReadEnum(root, "dataType", TwinCATDataType.DInt);
def = new TwinCATTagDefinition(
Name: reference, DeviceHostAddress: deviceHostAddress, SymbolPath: symbolPath,
DataType: dataType, Writable: true);
return true;
}
catch (JsonException) { return false; }
catch (FormatException) { return false; }
catch (InvalidOperationException) { return false; }
}
private static TEnum ReadEnum<TEnum>(JsonElement o, string name, TEnum fallback) where TEnum : struct, Enum
=> o.TryGetProperty(name, out var e) && e.ValueKind == JsonValueKind.String
&& Enum.TryParse<TEnum>(e.GetString(), ignoreCase: true, out var v) ? v : fallback;
private static string ReadString(JsonElement o, string name)
=> o.TryGetProperty(name, out var e) && e.ValueKind == JsonValueKind.String
? e.GetString() ?? "" : "";
}