fix(ablegacy): Test Connect normalises the probe address like the driver (#660)

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
Joseph Doherty
2026-10-09 06:01:35 -04:00
parent 98c00904e7
commit c0fbe74693
5 changed files with 78 additions and 3 deletions
@@ -693,7 +693,7 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
LibplctagPlcAttribute: state.Profile.LibplctagPlcAttribute,
// Normalised exactly like tag paths (PLC-5 octal I/O -> decimal); an unparseable probe address is passed through
// so the transport reports the failure as it always did.
TagName: AbLegacyAddress.TryParse(_options.Probe.ProbeAddress, state.Options.PlcFamily)?.ToLibplctagName()
TagName: AbLegacyProbeAddress.Normalise(_options.Probe.ProbeAddress, state.Options.PlcFamily)
?? _options.Probe.ProbeAddress!,
Timeout: _options.Probe.Timeout);
@@ -98,12 +98,18 @@ public sealed class AbLegacyDriverProbe : IDriverProbe
?? FirstProbeableTagAddress(opts, firstDevice)
?? "S:0";
// Normalise through the same helper as the driver's probe loop (#660): PLC-5 octal I/O -> decimal.
// An unparseable address is a clean failure here — the factory would otherwise throw outside the try.
var normalisedName = AbLegacyProbeAddress.Normalise(tagName, firstDevice?.PlcFamily ?? AbLegacyPlcFamily.Slc500);
if (normalisedName is null)
return new(false, $"Probe address '{tagName}' is not a valid AbLegacy address for this PLC family.", null);
var p = new AbLegacyTagCreateParams(
Gateway: parsed.Gateway,
Port: parsed.Port,
CipPath: parsed.CipPath,
LibplctagPlcAttribute: profile.LibplctagPlcAttribute,
TagName: tagName,
TagName: normalisedName,
Timeout: timeout);
var factory = _tagFactory ?? (AbLegacyTransportResolver.Resolve(opts) == AbLegacyTransport.Native
@@ -0,0 +1,16 @@
using ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.PlcFamilies;
namespace ZB.MOM.WW.OtOpcUa.Driver.AbLegacy;
/// <summary>
/// The single authority that turns an operator-authored probe address into the name handed to the tag
/// factory: family-aware parse (PLC-5 <c>I:</c>/<c>O:</c> octal indices become decimal) then
/// <see cref="AbLegacyAddress.ToLibplctagName"/> — the same normalisation tag paths get. Shared by the
/// driver's probe loop and the Test Connect probe (#660).
/// </summary>
internal static class AbLegacyProbeAddress
{
/// <summary>Returns the normalised name, or null when <paramref name="address"/> does not parse for the family.</summary>
public static string? Normalise(string? address, AbLegacyPlcFamily family) =>
AbLegacyAddress.TryParse(address, family)?.ToLibplctagName();
}