feat(s7): resolve equipment-tag refs (read + write) via EquipmentTagRefResolver
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
using System.Text.Json;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Driver.S7;
|
||||
|
||||
/// <summary>Parses an equipment tag's <c>TagConfig</c> JSON (the shape authored by the AdminUI
|
||||
/// <c>S7TagConfigModel</c> — <c>address</c> / <c>dataType</c> / <c>stringLength</c>) into a transient
|
||||
/// <see cref="S7TagDefinition"/> whose <see cref="S7TagDefinition.Name"/> equals the reference string
|
||||
/// itself, so a value the driver publishes back keys the runtime's forward router correctly.</summary>
|
||||
public static class S7EquipmentTagParser
|
||||
{
|
||||
/// <summary>S7 string max length (DBSTRING header reserves 2 bytes; 254 chars max).</summary>
|
||||
private const int MaxStringLength = 254;
|
||||
|
||||
/// <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 an S7 address object.</returns>
|
||||
public static bool TryParse(string reference, out S7TagDefinition 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("address", out var addrEl)
|
||||
|| addrEl.ValueKind != JsonValueKind.String
|
||||
|| !root.TryGetProperty("dataType", out _))
|
||||
return false;
|
||||
var address = addrEl.GetString();
|
||||
if (string.IsNullOrWhiteSpace(address)) return false;
|
||||
var dataType = ReadEnum(root, "dataType", S7DataType.Int16);
|
||||
var stringLength = ReadInt(root, "stringLength");
|
||||
// Range-guard rather than truncate: an S7 string can't exceed 254 chars, and a
|
||||
// negative length is meaningless — reject so a malformed blob can't slip through.
|
||||
if (stringLength < 0 || stringLength > MaxStringLength) return false;
|
||||
def = new S7TagDefinition(
|
||||
Name: reference,
|
||||
Address: address,
|
||||
DataType: dataType,
|
||||
Writable: true, // node-level authz governs writes
|
||||
StringLength: stringLength == 0 ? MaxStringLength : stringLength);
|
||||
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 int ReadInt(JsonElement o, string name)
|
||||
=> o.TryGetProperty(name, out var e) && e.ValueKind == JsonValueKind.Number
|
||||
&& e.TryGetInt32(out var v) ? v : 0;
|
||||
}
|
||||
Reference in New Issue
Block a user