feat(s7): STRING/WSTRING/CHAR/WCHAR and DTL/DATE/TOD/TIME/S5TIME codecs, TSAP/connection-type override, negotiated PDU surfaced (#632 #288 #289 #294 #295)

New S7DataType members WString/Char/WChar/Dtl/Date/Tod/Time/S5Time mapped onto existing
DriverDataType (String / DateTime / Int32 ms); writes refuse out-of-range with BadOutOfRange.
Optional localTsap/remoteTsap/connectionType through options, factory JSON, probe and AdminUI form.
NegotiatedPduSize snapshotted at connect and exposed via GetDiagnostics (DriverHealth has no bag).

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
Joseph Doherty
2026-10-08 14:31:44 -04:00
parent d898262c4a
commit 34c52defb3
18 changed files with 1430 additions and 31 deletions
@@ -105,4 +105,37 @@ public sealed class S7DriverPageFormSerializationTests
roundTripped.Probe.Timeout.ShouldBe(TimeSpan.FromSeconds(4));
roundTripped.ProbeTimeoutSeconds.ShouldBe(20);
}
[Fact]
public void FormModel_RoundTrip_PreservesTsapOverrides()
{
var opts = new S7DriverOptions
{
Host = "192.168.1.50",
LocalTsap = "01.00",
RemoteTsap = "03.01",
};
var back = S7DriverForm.FormModel.FromOptions(opts).ToOptions();
back.LocalTsap.ShouldBe("01.00");
back.RemoteTsap.ShouldBe("03.01");
back.ConnectionType.ShouldBeNull();
var withType = S7DriverForm.FormModel.FromOptions(new S7DriverOptions { ConnectionType = S7ConnectionType.OP }).ToOptions();
withType.ConnectionType.ShouldBe(S7ConnectionType.OP);
// Defaults stay absent: a blank form must not invent an override.
var blank = S7DriverForm.FormModel.FromOptions(new S7DriverOptions()).ToOptions();
blank.LocalTsap.ShouldBeNull();
blank.RemoteTsap.ShouldBeNull();
blank.ConnectionType.ShouldBeNull();
}
[Fact]
public void ConnectionType_serialises_as_a_string_the_factory_binds()
{
var json = JsonSerializer.Serialize(
new S7DriverOptions { ConnectionType = S7ConnectionType.PG },
new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, Converters = { new JsonStringEnumConverter() } });
json.ShouldContain("\"connectionType\":\"PG\"");
}
}
@@ -112,6 +112,14 @@ public sealed class S7TagConfigModelTests
[InlineData("Float64")]
[InlineData("String")]
[InlineData("DateTime")]
[InlineData("WString")]
[InlineData("Char")]
[InlineData("WChar")]
[InlineData("Dtl")]
[InlineData("Date")]
[InlineData("Tod")]
[InlineData("Time")]
[InlineData("S5Time")]
public void Validate_rejects_wide_type_arrays(string dataType)
{
var m = S7TagConfigModel.FromJson(