64e3fbe035
v2-ci / build (push) Failing after 1m43s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
Adds <summary>, <param>, <typeparam>, and <inheritdoc/> tags to public members surfaced by commentchecker — resolves 5,847 of 5,869 issues (99.6%) across three /fixdocs passes.
58 lines
2.3 KiB
C#
58 lines
2.3 KiB
C#
namespace ZB.MOM.WW.OtOpcUa.Driver.AbLegacy;
|
|
|
|
/// <summary>
|
|
/// Parsed <c>ab://gateway[:port]/cip-path</c> host-address string for AB Legacy devices.
|
|
/// Same format as AbCip — PCCC-over-EIP uses the same gateway + optional routing path as
|
|
/// the CIP family (a PLC-5 bridged through a ControlLogix chassis takes the full CIP path;
|
|
/// a direct-wired SLC 500 uses an empty path).
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Parser duplicated from AbCipHostAddress rather than shared because the two drivers ship
|
|
/// independently + a shared helper would force a reference between them. If a third AB
|
|
/// driver appears, extract into Core.Abstractions.
|
|
/// </remarks>
|
|
public sealed record AbLegacyHostAddress(string Gateway, int Port, string CipPath)
|
|
{
|
|
public const int DefaultEipPort = 44818;
|
|
|
|
/// <inheritdoc />
|
|
public override string ToString() => Port == DefaultEipPort
|
|
? $"ab://{Gateway}/{CipPath}"
|
|
: $"ab://{Gateway}:{Port}/{CipPath}";
|
|
|
|
/// <summary>Attempts to parse an AB host address string in the format ab://gateway[:port]/cip-path.</summary>
|
|
/// <param name="value">The host address string to parse.</param>
|
|
/// <returns>The parsed host address, or null if the format is invalid.</returns>
|
|
public static AbLegacyHostAddress? TryParse(string? value)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(value)) return null;
|
|
const string prefix = "ab://";
|
|
if (!value.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) return null;
|
|
|
|
var remainder = value[prefix.Length..];
|
|
var slashIdx = remainder.IndexOf('/');
|
|
if (slashIdx < 0) return null;
|
|
|
|
var authority = remainder[..slashIdx];
|
|
var cipPath = remainder[(slashIdx + 1)..];
|
|
if (string.IsNullOrEmpty(authority)) return null;
|
|
|
|
var port = DefaultEipPort;
|
|
var colonIdx = authority.LastIndexOf(':');
|
|
string gateway;
|
|
if (colonIdx >= 0)
|
|
{
|
|
gateway = authority[..colonIdx];
|
|
if (!int.TryParse(authority[(colonIdx + 1)..], out port) || port is <= 0 or > 65535)
|
|
return null;
|
|
}
|
|
else
|
|
{
|
|
gateway = authority;
|
|
}
|
|
if (string.IsNullOrEmpty(gateway)) return null;
|
|
|
|
return new AbLegacyHostAddress(gateway, port, cipPath);
|
|
}
|
|
}
|