feat(dcl): Layer C runtime wires new OPC UA settings through to OPC SDK

OpcUaConnectionOptions record gains DiscardOldest, SubscriptionPriority,
SubscriptionDisplayName, TimestampsToReturn, plus OpcUaDeadbandOptions and
OpcUaUserIdentityOptions nullable sub-records.

OpcUaDataConnection.ConnectAsync copies all new fields from the typed
OpcUaEndpointConfig (including the Deadband and UserIdentity sub-objects)
into the OpcUaConnectionOptions record.

RealOpcUaClient:
- BuildUserIdentity translates TokenType into Opc.Ua.UserIdentity:
  Anonymous → null, UsernamePassword → new UserIdentity(name, utf8(pass)),
  X509Certificate → new UserIdentity(X509CertificateLoader.LoadPkcs12FromFile(...)).
- Subscription uses opts.SubscriptionDisplayName and opts.SubscriptionPriority.
- MonitoredItem.DiscardOldest is opts.DiscardOldest (was hardcoded true).
- BuildDataChangeFilter materializes a DataChangeFilter when Deadband is set.
- ReadAsync uses MapTimestampsToReturn for opts.TimestampsToReturn (was hardcoded Source).

X509CertificateLoader replaces obsolete X509Certificate2(string,string) ctor
(SYSLIB0057 on .NET 10). UserIdentity(string,byte[]) ctor used because the
(string,string) overload was removed in OPC Foundation 1.5.378.106.
This commit is contained in:
Joseph Doherty
2026-05-12 02:26:15 -04:00
parent b60a8ef409
commit e6a5b558f3
3 changed files with 76 additions and 6 deletions
@@ -61,7 +61,19 @@ public class OpcUaDataConnection : IDataConnection
SamplingIntervalMs: config.SamplingIntervalMs,
QueueSize: config.QueueSize,
SecurityMode: config.SecurityMode.ToString(),
AutoAcceptUntrustedCerts: config.AutoAcceptUntrustedCerts);
AutoAcceptUntrustedCerts: config.AutoAcceptUntrustedCerts,
DiscardOldest: config.DiscardOldest,
SubscriptionPriority: config.SubscriptionPriority,
SubscriptionDisplayName: config.SubscriptionDisplayName,
TimestampsToReturn: config.TimestampsToReturn.ToString(),
Deadband: config.Deadband is { } db
? new OpcUaDeadbandOptions(db.Type.ToString(), db.Value)
: null,
UserIdentity: config.UserIdentity is { } ui
? new OpcUaUserIdentityOptions(
ui.TokenType.ToString(), ui.Username, ui.Password,
ui.CertificatePath, ui.CertificatePassword)
: null);
_status = ConnectionHealth.Connecting;