fix(abcip,ablegacy): pass a null libplctag path for an empty CIP route (Micro800 / unrouted MicroLogix)
The libplctag adapters assigned Tag.Path straight from the device's parsed CipPath. A device address with no route (ab://host:44818/ - the normal Micro800 form, and a MicroLogix with no route) parses to "", and libplctag rejects an empty path attribute with ErrorBadData; omitting the attribute (null) is what it accepts. So Micro800 could not connect on the default libplctag transport. This predates the native transport work and exists on master. Add an internal LibplctagPath.Normalize helper per driver project (blank -> null) and route all four Tag constructions through it (AbCip tag runtime, symbol-list enumerator, template reader; AbLegacy tag runtime). The runtime tag construction is extracted to an internal BuildTag so tests can inspect Tag.Path without connecting. Tests fail with Normalize reverted to identity. Update the Micro800 smoke-test comment: both transports are expected to pass.
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
namespace ZB.MOM.WW.OtOpcUa.Driver.AbCip;
|
||||
|
||||
/// <summary>
|
||||
/// Normalizes a parsed CIP route for libplctag's <c>Path</c> attribute. libplctag rejects an
|
||||
/// empty-string path with <c>ErrorBadData</c>; "no route" (Micro800, unrouted MicroLogix) must be
|
||||
/// expressed by omitting the attribute, i.e. <see langword="null"/>.
|
||||
/// </summary>
|
||||
internal static class LibplctagPath
|
||||
{
|
||||
/// <summary>Returns <see langword="null"/> for a null, empty or whitespace path; otherwise the path unchanged.</summary>
|
||||
/// <param name="path">The parsed CIP path.</param>
|
||||
public static string? Normalize(string? path) => string.IsNullOrWhiteSpace(path) ? null : path;
|
||||
}
|
||||
@@ -37,7 +37,7 @@ internal static class LibplctagListingReader
|
||||
internal static Tag BuildSymbolListTag(AbCipTagCreateParams deviceParams, string listingName = "@tags") => new()
|
||||
{
|
||||
Gateway = deviceParams.LibplctagGateway,
|
||||
Path = deviceParams.CipPath,
|
||||
Path = LibplctagPath.Normalize(deviceParams.CipPath),
|
||||
PlcType = MapPlcType(deviceParams.LibplctagPlcAttribute),
|
||||
Protocol = Protocol.ab_eip,
|
||||
Name = listingName,
|
||||
|
||||
@@ -18,12 +18,18 @@ internal sealed class LibplctagTagRuntime : IAbCipTagRuntime
|
||||
/// <param name="p">The tag creation parameters.</param>
|
||||
public LibplctagTagRuntime(AbCipTagCreateParams p)
|
||||
{
|
||||
_tag = new Tag
|
||||
_tag = BuildTag(p);
|
||||
}
|
||||
|
||||
/// <summary>Builds the (uninitialized) libplctag tag for <paramref name="p"/>.</summary>
|
||||
/// <param name="p">The tag creation parameters.</param>
|
||||
internal static Tag BuildTag(AbCipTagCreateParams p) =>
|
||||
new Tag
|
||||
{
|
||||
// host:port — see AbLegacyTagCreateParams/AbCipTagCreateParams.LibplctagGateway.
|
||||
// Passing p.Gateway alone drops the authored port onto libplctag's 44818 default (#534).
|
||||
Gateway = p.LibplctagGateway,
|
||||
Path = p.CipPath,
|
||||
Path = LibplctagPath.Normalize(p.CipPath),
|
||||
PlcType = MapPlcType(p.LibplctagPlcAttribute),
|
||||
Protocol = Protocol.ab_eip,
|
||||
Name = p.TagName,
|
||||
@@ -33,7 +39,6 @@ internal sealed class LibplctagTagRuntime : IAbCipTagRuntime
|
||||
// count so libplctag pulls every element in one CIP read; scalar tags pass 1.
|
||||
ElementCount = p.ElementCount > 1 ? p.ElementCount : 1,
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task InitializeAsync(CancellationToken cancellationToken) =>
|
||||
|
||||
@@ -39,7 +39,7 @@ internal sealed class LibplctagTemplateReader : IAbCipTemplateReader
|
||||
internal static Tag BuildTemplateTag(AbCipTagCreateParams deviceParams, uint templateInstanceId) => new()
|
||||
{
|
||||
Gateway = deviceParams.LibplctagGateway,
|
||||
Path = deviceParams.CipPath,
|
||||
Path = LibplctagPath.Normalize(deviceParams.CipPath),
|
||||
PlcType = MapPlcType(deviceParams.LibplctagPlcAttribute),
|
||||
Protocol = Protocol.ab_eip,
|
||||
Name = $"@udt/{templateInstanceId}",
|
||||
|
||||
@@ -17,19 +17,24 @@ internal sealed class LibplctagLegacyTagRuntime : IAbLegacyTagRuntime
|
||||
/// <param name="p">The parameters for tag creation.</param>
|
||||
public LibplctagLegacyTagRuntime(AbLegacyTagCreateParams p)
|
||||
{
|
||||
_tag = new Tag
|
||||
_tag = BuildTag(p);
|
||||
}
|
||||
|
||||
/// <summary>Builds the (uninitialized) libplctag tag for <paramref name="p"/>.</summary>
|
||||
/// <param name="p">The tag creation parameters.</param>
|
||||
internal static Tag BuildTag(AbLegacyTagCreateParams p) =>
|
||||
new Tag
|
||||
{
|
||||
// host:port — see AbLegacyTagCreateParams/AbCipTagCreateParams.LibplctagGateway.
|
||||
// Passing p.Gateway alone drops the authored port onto libplctag's 44818 default (#534).
|
||||
Gateway = p.LibplctagGateway,
|
||||
Path = p.CipPath,
|
||||
Path = LibplctagPath.Normalize(p.CipPath),
|
||||
PlcType = MapPlcType(p.LibplctagPlcAttribute),
|
||||
Protocol = Protocol.ab_eip, // PCCC-over-EIP; libplctag routes via the PlcType-specific PCCC layer
|
||||
Name = p.TagName,
|
||||
Timeout = p.Timeout,
|
||||
ElementCount = p.ElementCount > 1 ? p.ElementCount : null,
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task InitializeAsync(CancellationToken cancellationToken) =>
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace ZB.MOM.WW.OtOpcUa.Driver.AbLegacy;
|
||||
|
||||
/// <summary>
|
||||
/// Normalizes a parsed CIP route for libplctag's <c>Path</c> attribute. libplctag rejects an
|
||||
/// empty-string path with <c>ErrorBadData</c>; "no route" (Micro800, unrouted MicroLogix) must be
|
||||
/// expressed by omitting the attribute, i.e. <see langword="null"/>.
|
||||
/// </summary>
|
||||
internal static class LibplctagPath
|
||||
{
|
||||
/// <summary>Returns <see langword="null"/> for a null, empty or whitespace path; otherwise the path unchanged.</summary>
|
||||
/// <param name="path">The parsed CIP path.</param>
|
||||
public static string? Normalize(string? path) => string.IsNullOrWhiteSpace(path) ? null : path;
|
||||
}
|
||||
Reference in New Issue
Block a user