docs: backfill XML documentation across 756 files
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.
This commit is contained in:
Joseph Doherty
2026-05-28 08:10:17 -04:00
parent f9fc7dd2e1
commit 64e3fbe035
756 changed files with 9876 additions and 96 deletions
@@ -32,6 +32,7 @@ public sealed record AbLegacyAddress(
int? BitIndex,
string? SubElement)
{
/// <summary>Converts the address to the libplctag library address format.</summary>
public string ToLibplctagName()
{
var file = FileNumber is null ? FileLetter : $"{FileLetter}{FileNumber}";
@@ -41,6 +42,8 @@ public sealed record AbLegacyAddress(
return wordPart;
}
/// <summary>Attempts to parse a string into an AB legacy address.</summary>
/// <param name="value">The address string to parse.</param>
public static AbLegacyAddress? TryParse(string? value)
{
if (string.IsNullOrWhiteSpace(value)) return null;
@@ -31,6 +31,9 @@ public enum AbLegacyDataType
/// <summary>Map a PCCC data type to the driver-surface <see cref="DriverDataType"/>.</summary>
public static class AbLegacyDataTypeExtensions
{
/// <summary>Converts an AbLegacyDataType to the corresponding DriverDataType.</summary>
/// <param name="t">The PCCC data type to convert.</param>
/// <returns>The mapped driver data type.</returns>
public static DriverDataType ToDriverDataType(this AbLegacyDataType t) => t switch
{
AbLegacyDataType.Bit => DriverDataType.Boolean,
@@ -28,9 +28,23 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
// observes the most recently written value.
private volatile DriverHealth _health = new(DriverState.Unknown, null, null);
/// <summary>
/// Occurs when data values change.
/// </summary>
public event EventHandler<DataChangeEventArgs>? OnDataChange;
/// <summary>
/// Occurs when host status changes.
/// </summary>
public event EventHandler<HostStatusChangedEventArgs>? OnHostStatusChanged;
/// <summary>
/// Initializes a new instance of the <see cref="AbLegacyDriver"/> class.
/// </summary>
/// <param name="options">The driver options.</param>
/// <param name="driverInstanceId">The driver instance identifier.</param>
/// <param name="tagFactory">The tag factory, or <c>null</c> to use the default.</param>
/// <param name="logger">The logger, or <c>null</c> to use the null logger.</param>
public AbLegacyDriver(AbLegacyDriverOptions options, string driverInstanceId,
IAbLegacyTagFactory? tagFactory = null,
ILogger<AbLegacyDriver>? logger = null)
@@ -46,9 +60,22 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
OnDataChange?.Invoke(this, new DataChangeEventArgs(handle, tagRef, snapshot)));
}
/// <summary>
/// Gets the driver instance identifier.
/// </summary>
public string DriverInstanceId => _driverInstanceId;
/// <summary>
/// Gets the driver type.
/// </summary>
public string DriverType => "AbLegacy";
/// <summary>
/// Initializes the driver asynchronously.
/// </summary>
/// <param name="driverConfigJson">The driver configuration JSON.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A task representing the asynchronous operation.</returns>
public Task InitializeAsync(string driverConfigJson, CancellationToken cancellationToken)
{
_health = new DriverHealth(DriverState.Initializing, null, null);
@@ -121,12 +148,23 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
return Task.CompletedTask;
}
/// <summary>
/// Reinitializes the driver asynchronously.
/// </summary>
/// <param name="driverConfigJson">The driver configuration JSON.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A task representing the asynchronous operation.</returns>
public async Task ReinitializeAsync(string driverConfigJson, CancellationToken cancellationToken)
{
await ShutdownAsync(cancellationToken).ConfigureAwait(false);
await InitializeAsync(driverConfigJson, cancellationToken).ConfigureAwait(false);
}
/// <summary>
/// Shuts down the driver asynchronously.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A task representing the asynchronous operation.</returns>
public async Task ShutdownAsync(CancellationToken cancellationToken)
{
await _poll.DisposeAsync().ConfigureAwait(false);
@@ -142,16 +180,46 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
_health = new DriverHealth(DriverState.Unknown, _health.LastSuccessfulRead, null);
}
/// <summary>
/// Gets the driver health status.
/// </summary>
/// <returns>The driver health status.</returns>
public DriverHealth GetHealth() => _health;
/// <summary>
/// Gets the memory footprint of the driver.
/// </summary>
/// <returns>The memory footprint in bytes.</returns>
public long GetMemoryFootprint() => 0;
/// <summary>
/// Flushes optional caches asynchronously.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A task representing the asynchronous operation.</returns>
public Task FlushOptionalCachesAsync(CancellationToken cancellationToken) => Task.CompletedTask;
/// <summary>
/// Gets the device count.
/// </summary>
internal int DeviceCount => _devices.Count;
/// <summary>
/// Gets the device state for the specified host address.
/// </summary>
/// <param name="hostAddress">The host address.</param>
/// <returns>The device state, or <c>null</c> if not found.</returns>
internal DeviceState? GetDeviceState(string hostAddress) =>
_devices.TryGetValue(hostAddress, out var s) ? s : null;
// ---- IReadable ----
/// <summary>
/// Reads data values asynchronously.
/// </summary>
/// <param name="fullReferences">The full references to read.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A list of data value snapshots.</returns>
public async Task<IReadOnlyList<DataValueSnapshot>> ReadAsync(
IReadOnlyList<string> fullReferences, CancellationToken cancellationToken)
{
@@ -237,6 +305,12 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
// ---- IWritable ----
/// <summary>
/// Writes data values asynchronously.
/// </summary>
/// <param name="writes">The write requests.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A list of write results.</returns>
public async Task<IReadOnlyList<WriteResult>> WriteAsync(
IReadOnlyList<WriteRequest> writes, CancellationToken cancellationToken)
{
@@ -326,6 +400,12 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
// ---- ITagDiscovery ----
/// <summary>
/// Discovers tags and populates the address space asynchronously.
/// </summary>
/// <param name="builder">The address space builder.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A task representing the asynchronous operation.</returns>
public Task DiscoverAsync(IAddressSpaceBuilder builder, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(builder);
@@ -364,10 +444,23 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
// ---- ISubscribable (polling overlay via shared engine) ----
/// <summary>
/// Subscribes to data changes asynchronously.
/// </summary>
/// <param name="fullReferences">The full references to subscribe to.</param>
/// <param name="publishingInterval">The publishing interval.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A subscription handle.</returns>
public Task<ISubscriptionHandle> SubscribeAsync(
IReadOnlyList<string> fullReferences, TimeSpan publishingInterval, CancellationToken cancellationToken) =>
Task.FromResult(_poll.Subscribe(fullReferences, publishingInterval));
/// <summary>
/// Unsubscribes from data changes asynchronously.
/// </summary>
/// <param name="handle">The subscription handle.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A task representing the asynchronous operation.</returns>
public Task UnsubscribeAsync(ISubscriptionHandle handle, CancellationToken cancellationToken)
{
_poll.Unsubscribe(handle);
@@ -376,6 +469,10 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
// ---- IHostConnectivityProbe ----
/// <summary>
/// Gets the host connectivity statuses.
/// </summary>
/// <returns>A list of host connectivity statuses.</returns>
public IReadOnlyList<HostConnectivityStatus> GetHostStatuses() =>
[.. _devices.Values.Select(s => new HostConnectivityStatus(s.Options.HostAddress, s.HostState, s.HostStateChangedUtc))];
@@ -462,6 +559,8 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
/// <see cref="DeviceCount"/> before relying on per-tag routing.</item>
/// </list>
/// </summary>
/// <param name="fullReference">The full reference to resolve.</param>
/// <returns>The host address for the reference.</returns>
public string ResolveHost(string fullReference)
{
if (_tagsByName.TryGetValue(fullReference, out var def))
@@ -638,6 +737,10 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
_health = new DriverHealth(DriverState.Unknown, _health.LastSuccessfulRead, null);
}
/// <summary>
/// Disposes the driver asynchronously.
/// </summary>
/// <returns>A task representing the asynchronous disposal.</returns>
public async ValueTask DisposeAsync() => await ShutdownAsync(CancellationToken.None).ConfigureAwait(false);
internal sealed class DeviceState(
@@ -645,8 +748,19 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
AbLegacyDeviceOptions options,
AbLegacyPlcFamilyProfile profile)
{
/// <summary>
/// Gets the parsed host address.
/// </summary>
public AbLegacyHostAddress ParsedAddress { get; } = parsedAddress;
/// <summary>
/// Gets the device options.
/// </summary>
public AbLegacyDeviceOptions Options { get; } = options;
/// <summary>
/// Gets the PLC family profile.
/// </summary>
public AbLegacyPlcFamilyProfile Profile { get; } = profile;
/// <summary>
@@ -686,11 +800,21 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
/// </summary>
private readonly System.Collections.Concurrent.ConcurrentDictionary<string, SemaphoreSlim> _creationLocks = new(StringComparer.OrdinalIgnoreCase);
/// <summary>
/// Gets or creates the creation lock for the specified key.
/// </summary>
/// <param name="key">The lock key.</param>
/// <returns>The semaphore slim for the key.</returns>
public SemaphoreSlim GetCreationLock(string key) =>
_creationLocks.GetOrAdd(key, _ => new SemaphoreSlim(1, 1));
private readonly System.Collections.Concurrent.ConcurrentDictionary<string, SemaphoreSlim> _rmwLocks = new();
/// <summary>
/// Gets or creates the read-modify-write lock for the specified parent name.
/// </summary>
/// <param name="parentName">The parent name.</param>
/// <returns>The semaphore slim for the parent.</returns>
public SemaphoreSlim GetRmwLock(string parentName) =>
_rmwLocks.GetOrAdd(parentName, _ => new SemaphoreSlim(1, 1));
@@ -705,13 +829,34 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
/// or value is never observed mid-update by another thread. Keyed by tag name, which
/// is also the <see cref="Runtimes"/> dictionary key.
/// </summary>
/// <param name="tagName">The tag name.</param>
/// <returns>The semaphore slim for the tag.</returns>
public SemaphoreSlim GetRuntimeLock(string tagName) =>
_runtimeLocks.GetOrAdd(tagName, _ => new SemaphoreSlim(1, 1));
/// <summary>
/// Gets the probe synchronization lock.
/// </summary>
public object ProbeLock { get; } = new();
/// <summary>
/// Gets or sets the host state.
/// </summary>
public HostState HostState { get; set; } = HostState.Unknown;
/// <summary>
/// Gets or sets the UTC time when the host state last changed.
/// </summary>
public DateTime HostStateChangedUtc { get; set; } = DateTime.UtcNow;
/// <summary>
/// Gets or sets the cancellation token source for the probe loop.
/// </summary>
public CancellationTokenSource? ProbeCts { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the probe has been initialized.
/// </summary>
public bool ProbeInitialized { get; set; }
/// <summary>
@@ -725,6 +870,9 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover
/// </summary>
public bool FirstNonZeroStatusLogged { get; set; }
/// <summary>
/// Disposes all cached tag runtimes.
/// </summary>
public void DisposeRuntimes()
{
foreach (var r in Runtimes.Values) r.Dispose();
@@ -23,15 +23,30 @@ public static class AbLegacyDriverFactoryExtensions
/// the driver runs with the null logger (existing tests and standalone callers stay
/// unchanged). Mirrors the Modbus driver registration pattern.
/// </summary>
/// <param name="registry">The driver factory registry to register with.</param>
/// <param name="loggerFactory">Optional logger factory for driver instances.</param>
public static void Register(DriverFactoryRegistry registry, ILoggerFactory? loggerFactory = null)
{
ArgumentNullException.ThrowIfNull(registry);
registry.Register(DriverTypeName, (id, json) => CreateInstance(id, json, loggerFactory));
}
/// <summary>
/// Creates an instance of the AB Legacy driver from configuration.
/// </summary>
/// <param name="driverInstanceId">The unique identifier for this driver instance.</param>
/// <param name="driverConfigJson">The driver configuration as a JSON string.</param>
/// <returns>A configured <see cref="AbLegacyDriver"/> instance.</returns>
internal static AbLegacyDriver CreateInstance(string driverInstanceId, string driverConfigJson)
=> CreateInstance(driverInstanceId, driverConfigJson, loggerFactory: null);
/// <summary>
/// Creates an instance of the AB Legacy driver with optional logger.
/// </summary>
/// <param name="driverInstanceId">The unique identifier for this driver instance.</param>
/// <param name="driverConfigJson">The driver configuration as a JSON string.</param>
/// <param name="loggerFactory">Optional logger factory for the driver instance.</param>
/// <returns>A configured <see cref="AbLegacyDriver"/> instance.</returns>
internal static AbLegacyDriver CreateInstance(string driverInstanceId, string driverConfigJson, ILoggerFactory? loggerFactory)
{
ArgumentException.ThrowIfNullOrWhiteSpace(driverInstanceId);
@@ -105,34 +120,98 @@ public static class AbLegacyDriverFactoryExtensions
internal sealed class AbLegacyDriverConfigDto
{
/// <summary>
/// Gets or sets the timeout in milliseconds for operations.
/// </summary>
public int? TimeoutMs { get; init; }
/// <summary>
/// Gets or sets the list of devices to connect to.
/// </summary>
public List<AbLegacyDeviceDto>? Devices { get; init; }
/// <summary>
/// Gets or sets the list of tags to monitor.
/// </summary>
public List<AbLegacyTagDto>? Tags { get; init; }
/// <summary>
/// Gets or sets the probe configuration.
/// </summary>
public AbLegacyProbeDto? Probe { get; init; }
}
internal sealed class AbLegacyDeviceDto
{
/// <summary>
/// Gets or sets the host address of the device.
/// </summary>
public string? HostAddress { get; init; }
/// <summary>
/// Gets or sets the PLC family.
/// </summary>
public string? PlcFamily { get; init; }
/// <summary>
/// Gets or sets the device name.
/// </summary>
public string? DeviceName { get; init; }
}
internal sealed class AbLegacyTagDto
{
/// <summary>
/// Gets or sets the tag name.
/// </summary>
public string? Name { get; init; }
/// <summary>
/// Gets or sets the device host address.
/// </summary>
public string? DeviceHostAddress { get; init; }
/// <summary>
/// Gets or sets the tag address.
/// </summary>
public string? Address { get; init; }
/// <summary>
/// Gets or sets the data type.
/// </summary>
public string? DataType { get; init; }
/// <summary>
/// Gets or sets whether the tag is writable.
/// </summary>
public bool? Writable { get; init; }
/// <summary>
/// Gets or sets whether write is idempotent.
/// </summary>
public bool? WriteIdempotent { get; init; }
}
internal sealed class AbLegacyProbeDto
{
/// <summary>
/// Gets or sets whether probing is enabled.
/// </summary>
public bool? Enabled { get; init; }
/// <summary>
/// Gets or sets the probe interval in milliseconds.
/// </summary>
public int? IntervalMs { get; init; }
/// <summary>
/// Gets or sets the probe timeout in milliseconds.
/// </summary>
public int? TimeoutMs { get; init; }
/// <summary>
/// Gets or sets the probe address.
/// </summary>
public string? ProbeAddress { get; init; }
}
}
@@ -10,9 +10,16 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.AbLegacy;
/// </summary>
public sealed class AbLegacyDriverOptions
{
/// <summary>Gets or sets the list of PCCC devices to connect to.</summary>
public IReadOnlyList<AbLegacyDeviceOptions> Devices { get; init; } = [];
/// <summary>Gets or sets the list of PCCC tag definitions.</summary>
public IReadOnlyList<AbLegacyTagDefinition> Tags { get; init; } = [];
/// <summary>Gets or sets the probe (connectivity check) options.</summary>
public AbLegacyProbeOptions Probe { get; init; } = new();
/// <summary>Gets or sets the default timeout for read/write operations.</summary>
public TimeSpan Timeout { get; init; } = TimeSpan.FromSeconds(2);
}
@@ -35,10 +42,15 @@ public sealed record AbLegacyTagDefinition(
public sealed class AbLegacyProbeOptions
{
/// <summary>Gets or sets a value indicating whether connectivity probing is enabled.</summary>
public bool Enabled { get; init; } = true;
/// <summary>Gets or sets the interval between probe attempts.</summary>
public TimeSpan Interval { get; init; } = TimeSpan.FromSeconds(5);
/// <summary>Gets or sets the timeout for each probe operation.</summary>
public TimeSpan Timeout { get; init; } = TimeSpan.FromSeconds(2);
/// <summary>Probe address defaults to <c>S:0</c> (status file, first word) when null.</summary>
/// <summary>Gets or sets the probe address (defaults to <c>S:0</c> status file, first word).</summary>
public string? ProbeAddress { get; init; } = "S:0";
}
@@ -15,10 +15,14 @@ public sealed record AbLegacyHostAddress(string Gateway, int Port, string CipPat
{
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;
@@ -28,6 +28,8 @@ public static class AbLegacyStatusMapper
/// stays correct regardless of how the wrapper renumbers native PLCTAG_ERR_* constants
/// in future releases.
/// </summary>
/// <param name="status">The integer status code from libplctag.</param>
/// <returns>The corresponding OPC UA status code.</returns>
public static uint MapLibplctagStatus(int status) => MapLibplctagStatus((Status)status);
/// <summary>
@@ -35,6 +37,8 @@ public static class AbLegacyStatusMapper
/// the canonical core; the <c>int</c> overload exists only for the
/// <see cref="IAbLegacyTagRuntime.GetStatus"/> seam which boxes the enum as an int.
/// </summary>
/// <param name="status">The libplctag Status enum value.</param>
/// <returns>The corresponding OPC UA status code.</returns>
public static uint MapLibplctagStatus(Status status) => status switch
{
Status.Ok => Good,
@@ -59,6 +63,8 @@ public static class AbLegacyStatusMapper
/// the raw STS byte, so this method is not wired into the current read/write path.
/// It is retained as the reference mapping for future PCCC-STS inspection.
/// </summary>
/// <param name="sts">The PCCC STS byte.</param>
/// <returns>The corresponding OPC UA status code.</returns>
public static uint MapPcccStatus(byte sts) => sts switch
{
0x00 => Good,
@@ -7,16 +7,37 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.AbLegacy;
/// </summary>
public interface IAbLegacyTagRuntime : IDisposable
{
/// <summary>Initializes the tag runtime.</summary>
/// <param name="cancellationToken">Cancellation token for the operation.</param>
Task InitializeAsync(CancellationToken cancellationToken);
/// <summary>Reads the current value of the tag.</summary>
/// <param name="cancellationToken">Cancellation token for the operation.</param>
Task ReadAsync(CancellationToken cancellationToken);
/// <summary>Writes the encoded value to the tag.</summary>
/// <param name="cancellationToken">Cancellation token for the operation.</param>
Task WriteAsync(CancellationToken cancellationToken);
/// <summary>Gets the current status of the tag operation.</summary>
int GetStatus();
/// <summary>Decodes the tag value according to the specified data type.</summary>
/// <param name="type">The data type to decode.</param>
/// <param name="bitIndex">Optional bit index for bit-level access.</param>
object? DecodeValue(AbLegacyDataType type, int? bitIndex);
/// <summary>Encodes a value for writing to the tag.</summary>
/// <param name="type">The data type to encode.</param>
/// <param name="bitIndex">Optional bit index for bit-level access.</param>
/// <param name="value">The value to encode.</param>
void EncodeValue(AbLegacyDataType type, int? bitIndex, object? value);
}
public interface IAbLegacyTagFactory
{
/// <summary>Creates a tag runtime instance with the specified parameters.</summary>
/// <param name="createParams">The tag creation parameters.</param>
IAbLegacyTagRuntime Create(AbLegacyTagCreateParams createParams);
}
@@ -12,6 +12,8 @@ internal sealed class LibplctagLegacyTagRuntime : IAbLegacyTagRuntime
{
private readonly Tag _tag;
/// <summary>Initializes a new instance of the <see cref="LibplctagLegacyTagRuntime"/> class.</summary>
/// <param name="p">The parameters for tag creation.</param>
public LibplctagLegacyTagRuntime(AbLegacyTagCreateParams p)
{
_tag = new Tag
@@ -25,12 +27,19 @@ internal sealed class LibplctagLegacyTagRuntime : IAbLegacyTagRuntime
};
}
/// <inheritdoc />
public Task InitializeAsync(CancellationToken cancellationToken) => _tag.InitializeAsync(cancellationToken);
/// <inheritdoc />
public Task ReadAsync(CancellationToken cancellationToken) => _tag.ReadAsync(cancellationToken);
/// <inheritdoc />
public Task WriteAsync(CancellationToken cancellationToken) => _tag.WriteAsync(cancellationToken);
/// <inheritdoc />
public int GetStatus() => (int)_tag.GetStatus();
/// <inheritdoc />
public object? DecodeValue(AbLegacyDataType type, int? bitIndex) => type switch
{
// When a bit suffix is present (e.g. B3:0/5) libplctag resolves the individual bit and
@@ -49,6 +58,7 @@ internal sealed class LibplctagLegacyTagRuntime : IAbLegacyTagRuntime
_ => null,
};
/// <inheritdoc />
public void EncodeValue(AbLegacyDataType type, int? bitIndex, object? value)
{
switch (type)
@@ -86,6 +96,7 @@ internal sealed class LibplctagLegacyTagRuntime : IAbLegacyTagRuntime
}
}
/// <inheritdoc />
public void Dispose() => _tag.Dispose();
private static PlcType MapPlcType(string attribute) => attribute switch
@@ -100,6 +111,9 @@ internal sealed class LibplctagLegacyTagRuntime : IAbLegacyTagRuntime
internal sealed class LibplctagLegacyTagFactory : IAbLegacyTagFactory
{
/// <summary>Creates a new libplctag-backed tag runtime instance.</summary>
/// <param name="createParams">The parameters for tag creation.</param>
/// <returns>A new tag runtime instance.</returns>
public IAbLegacyTagRuntime Create(AbLegacyTagCreateParams createParams) =>
new LibplctagLegacyTagRuntime(createParams);
}
@@ -11,6 +11,8 @@ public sealed record AbLegacyPlcFamilyProfile(
bool SupportsStringFile,
bool SupportsLongFile)
{
/// <summary>Gets the profile for the specified PLC family.</summary>
/// <param name="family">The PLC family.</param>
public static AbLegacyPlcFamilyProfile ForFamily(AbLegacyPlcFamily family) => family switch
{
AbLegacyPlcFamily.Slc500 => Slc500,