65 lines
2.4 KiB
C#
65 lines
2.4 KiB
C#
namespace ZB.MOM.WW.OtOpcUa.Driver.TwinCAT;
|
|
|
|
/// <summary>
|
|
/// Parsed TwinCAT AMS address — six-octet AMS Net ID + port. Canonical form
|
|
/// <c>ads://{netId}:{port}</c> where <c>netId</c> is five-dot-separated octets (six of them)
|
|
/// and <c>port</c> is the AMS service port (851 = TC3 PLC runtime 1, 852 = runtime 2, 801 /
|
|
/// 811 / 821 = TC2 PLC runtimes, 10000 = system service, etc.).
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Format examples:
|
|
/// <list type="bullet">
|
|
/// <item><c>ads://5.23.91.23.1.1:851</c> — remote TC3 runtime</item>
|
|
/// <item><c>ads://5.23.91.23.1.1</c> — defaults to port 851 (TC3 PLC runtime 1)</item>
|
|
/// <item><c>ads://127.0.0.1.1.1:851</c> — local loopback (when the router is local)</item>
|
|
/// </list>
|
|
/// <para>AMS Net ID is NOT an IP — it's a Beckhoff-specific identifier that the router
|
|
/// translates to an IP route. Typically the first four octets match the host's IPv4 and
|
|
/// the last two are <c>.1.1</c>, but the router can be configured otherwise.</para>
|
|
/// </remarks>
|
|
public sealed record TwinCATAmsAddress(string NetId, int Port)
|
|
{
|
|
/// <summary>Default AMS port — TC3 PLC runtime 1.</summary>
|
|
public const int DefaultPlcPort = 851;
|
|
|
|
public override string ToString() => Port == DefaultPlcPort
|
|
? $"ads://{NetId}"
|
|
: $"ads://{NetId}:{Port}";
|
|
|
|
public static TwinCATAmsAddress? TryParse(string? value)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(value)) return null;
|
|
const string prefix = "ads://";
|
|
if (!value.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) return null;
|
|
|
|
var body = value[prefix.Length..];
|
|
if (string.IsNullOrEmpty(body)) return null;
|
|
|
|
var colonIdx = body.LastIndexOf(':');
|
|
string netId;
|
|
var port = DefaultPlcPort;
|
|
if (colonIdx >= 0)
|
|
{
|
|
netId = body[..colonIdx];
|
|
if (!int.TryParse(body[(colonIdx + 1)..], out port) || port is <= 0 or > 65535)
|
|
return null;
|
|
}
|
|
else
|
|
{
|
|
netId = body;
|
|
}
|
|
|
|
if (!IsValidNetId(netId)) return null;
|
|
return new TwinCATAmsAddress(netId, port);
|
|
}
|
|
|
|
private static bool IsValidNetId(string netId)
|
|
{
|
|
var parts = netId.Split('.');
|
|
if (parts.Length != 6) return false;
|
|
foreach (var p in parts)
|
|
if (!byte.TryParse(p, out _)) return false;
|
|
return true;
|
|
}
|
|
}
|