@@ -163,7 +163,7 @@ public sealed class S7Driver(S7DriverOptions options, string driverInstanceId)
|
||||
_parsedByName[t.Name] = parsed;
|
||||
}
|
||||
|
||||
var plc = new Plc(_options.CpuType, _options.Host, _options.Port, _options.Rack, _options.Slot);
|
||||
var plc = BuildPlc();
|
||||
// S7netplus writes timeouts into the underlying TcpClient via Plc.WriteTimeout /
|
||||
// Plc.ReadTimeout (milliseconds). Set before OpenAsync so the handshake itself
|
||||
// honours the bound.
|
||||
@@ -889,6 +889,58 @@ public sealed class S7Driver(S7DriverOptions options, string driverInstanceId)
|
||||
private global::S7.Net.Plc RequirePlc() =>
|
||||
Plc ?? throw new InvalidOperationException("S7Driver not initialized");
|
||||
|
||||
/// <summary>
|
||||
/// Construct the underlying S7netplus <see cref="Plc"/> honouring
|
||||
/// <see cref="S7DriverOptions.TsapMode"/>, <see cref="S7DriverOptions.LocalTsap"/>,
|
||||
/// and <see cref="S7DriverOptions.RemoteTsap"/>. <see cref="TsapMode.Auto"/> falls
|
||||
/// back to the existing <c>(CpuType, host, port, rack, slot)</c> constructor so the
|
||||
/// change is opt-in for sites that don't need a non-default class. Other modes go
|
||||
/// through the raw-TSAP-pair overload, computing the pair from
|
||||
/// <see cref="S7TsapDefaults"/> and the configured rack/slot, then layering the
|
||||
/// caller-supplied <see cref="S7DriverOptions.LocalTsap"/> /
|
||||
/// <see cref="S7DriverOptions.RemoteTsap"/> on top.
|
||||
/// </summary>
|
||||
private Plc BuildPlc()
|
||||
{
|
||||
if (_options.TsapMode == TsapMode.Auto)
|
||||
{
|
||||
// Existing behaviour: S7netplus picks the TSAP pair via TsapPair.GetDefaultTsapPair
|
||||
// from CpuType + rack + slot. An explicit LocalTsap / RemoteTsap under Auto is
|
||||
// ignored on purpose — Auto means "let the library decide". Document this in s7.md.
|
||||
return new Plc(_options.CpuType, _options.Host, _options.Port, _options.Rack, _options.Slot);
|
||||
}
|
||||
|
||||
ushort localTsap;
|
||||
ushort remoteTsap;
|
||||
|
||||
if (_options.TsapMode == TsapMode.Other)
|
||||
{
|
||||
if (_options.LocalTsap is not ushort lt || _options.RemoteTsap is not ushort rt)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"S7DriverOptions.TsapMode = Other requires both LocalTsap and RemoteTsap to be set " +
|
||||
"(no class default exists for Other). Set both, or pick Pg / Op / S7Basic.");
|
||||
}
|
||||
localTsap = lt;
|
||||
remoteTsap = rt;
|
||||
}
|
||||
else
|
||||
{
|
||||
var classByte = S7TsapDefaults.HighByteFor(_options.TsapMode);
|
||||
// Compute defaults from the class + configured rack/slot, then let explicit
|
||||
// overrides win — so e.g. "TsapMode = Pg, LocalTsap = 0x0142" produces a PG-class
|
||||
// remote with a custom local for sites that need a fixed source-TSAP.
|
||||
localTsap = _options.LocalTsap ?? S7TsapDefaults.BuildLocalTsap(classByte);
|
||||
remoteTsap = _options.RemoteTsap ?? S7TsapDefaults.BuildRemoteTsap(
|
||||
classByte, _options.Rack, _options.Slot);
|
||||
}
|
||||
|
||||
var pair = new global::S7.Net.Protocol.TsapPair(
|
||||
new global::S7.Net.Protocol.Tsap((byte)(localTsap >> 8), (byte)(localTsap & 0xFF)),
|
||||
new global::S7.Net.Protocol.Tsap((byte)(remoteTsap >> 8), (byte)(remoteTsap & 0xFF)));
|
||||
return new Plc(_options.Host, _options.Port, pair);
|
||||
}
|
||||
|
||||
// ---- ITagDiscovery ----
|
||||
|
||||
public Task DiscoverAsync(IAddressSpaceBuilder builder, CancellationToken cancellationToken)
|
||||
|
||||
Reference in New Issue
Block a user