Merge #602(S7)/#610.2: S7 connect backoff, write-path worst-state-wins, Volatile health, factory logging, driver-side array writes

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
Joseph Doherty
2026-10-08 07:01:32 -04:00
12 changed files with 845 additions and 75 deletions
@@ -112,6 +112,26 @@ public sealed class S7TagConfigModel
+ string.Join(", ", Enum.GetNames<S7DataType>()) + ".";
}
// S7-016: array shape is judged against the driver's INIT guards, which THROW (failing the whole
// driver's init, not just this tag) for a wide-type array and for a writable Bool array. The
// isArray / arrayLength keys themselves belong to the TagModal's generic array controls
// (TagArrayConfig) and are intentionally not fields of this model, so read them off the key bag.
if (TagConfigJson.GetBool(_bag, "isArray"))
{
var dt = DataType;
if (dt is S7DataType.Int64 or S7DataType.UInt64 or S7DataType.Float64
or S7DataType.String or S7DataType.DateTime)
{
return $"S7 does not support {dt} arrays — use Bool (read-only), Byte, Int16, UInt16, Int32, "
+ "UInt32 or Float32 for an array tag, or a scalar tag.";
}
if (dt == S7DataType.Bool && (Writable ?? true))
{
return "A Bool array cannot be writable (a byte-granular write would clobber neighbouring bits) — "
+ "uncheck Writable, or use scalar Bool tags.";
}
}
// Gitea #554: the reader's remaining, non-enum refusal — a String tag whose 'stringLength' is
// negative or above 254 (S7 REJECTS it rather than clamping) — is not restated here. The verdict and
// the wording both come from the driver's own reader, via TagConfigParseGate.
@@ -226,7 +226,7 @@ public static class DriverFactoryBootstrap
// task, so the Tier A 5s Subscribe budget never covers the stream's lifetime.
Driver.MTConnect.MTConnectDriverFactoryExtensions.Register(registry, loggerFactory);
Driver.OpcUaClient.OpcUaClientDriverFactoryExtensions.Register(registry, loggerFactory, secretResolver);
Driver.S7.S7DriverFactoryExtensions.Register(registry);
Driver.S7.S7DriverFactoryExtensions.Register(registry, loggerFactory);
Driver.Sql.SqlDriverFactoryExtensions.Register(registry, loggerFactory);
Driver.TwinCAT.TwinCATDriverFactoryExtensions.Register(registry, loggerFactory);
}