using System.ComponentModel.DataAnnotations;
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
using ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.PlcFamilies;
namespace ZB.MOM.WW.OtOpcUa.Driver.AbLegacy;
///
/// AB Legacy (PCCC) driver configuration. One instance supports N devices (SLC 500 /
/// MicroLogix / PLC-5 / LogixPccc). AbLegacy ships separately from
/// AbCip because PCCC's file-based addressing (N7:0) and Logix's symbolic addressing
/// (Motor1.Speed) pull the abstraction in different directions.
///
public sealed class AbLegacyDriverOptions
{
/// Gets or sets the list of PCCC devices to connect to.
public IReadOnlyList Devices { get; init; } = [];
///
/// Authored raw tags this driver serves. The deploy artifact hands each authored raw
/// Tag as a (RawPath identity + driver TagConfig blob +
/// WriteIdempotent flag + owning ); the driver maps each
/// through into its RawPath → definition
/// table, routing each to its device by . AbLegacy has no
/// discovery protocol — the driver serves exactly these.
///
public IReadOnlyList RawTags { get; init; } = [];
///
/// Which transport stack the driver, its Test Connect probe and the CLI use. null (the
/// transport key absent) means "use the default": for
/// every family. is opt-in (final review I3: on a wire it is proven
/// only for N-file reads/writes and one F8 read). An explicit value always wins. The
/// effective transport is resolved in one place, AbLegacyTransportResolver.
/// Changing this takes effect when the driver instance is RECREATED, not on
/// ReinitializeAsync: the tag factory is chosen once in the constructor and held across
/// Shutdown+Initialize. A deploy that changes the driver config stops and respawns the instance
/// (DriverSpawnPlanner, #516), so an operator edit does recreate it.
///
/// Null is never written: an absent key IS the "use the default" encoding, so a round-trip
/// through any serializer (the AdminUI form included) keeps a defaulted driver defaulted rather than
/// pinning it to whatever the default happened to be on the day it was saved.
[System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)]
public AbLegacyTransport? Transport { get; init; }
/// Gets or sets the probe (connectivity check) options.
public AbLegacyProbeOptions Probe { get; init; } = new();
/// Gets or sets the default timeout for read/write operations.
public TimeSpan Timeout { get; init; } = TimeSpan.FromSeconds(2);
///
/// Timeout for the AdminUI Test Connect probe, in seconds. The AdminUI clamps to a
/// 60s server-side maximum; this default is what the form pre-fills for new instances.
///
[Display(Name = "Probe timeout (seconds)", Description = "Connection test timeout. Default 5s.", GroupName = "Diagnostics")]
[Range(1, 60)]
public int ProbeTimeoutSeconds { get; init; } = 5;
}
public sealed record AbLegacyDeviceOptions(
string HostAddress,
AbLegacyPlcFamily PlcFamily = AbLegacyPlcFamily.Slc500,
string? DeviceName = null);
///
/// One PCCC-backed OPC UA variable. is the canonical PCCC
/// file-address string that parses via AbLegacyAddress.TryParse.
///
///
/// Element count when the tag addresses a multi-element span of a PCCC data file (e.g. an
/// N7 integer file is inherently up to 256 words); for a scalar.
/// A PCCC data file holds at most (256) elements, so a
/// value above that is clamped where it is materialised/read. 1 is a valid one-element array exposed as a [1] OPC UA array node.
///
public sealed record AbLegacyTagDefinition(
string Name,
string DeviceHostAddress,
string Address,
AbLegacyDataType DataType,
bool Writable = true,
bool WriteIdempotent = false,
int? ArrayLength = null);
/// PCCC array-tag constants shared by the parser, discovery, and read paths.
public static class AbLegacyArray
{
///
/// Maximum element count for a single PCCC data file. The PCCC/DF1 protocol addresses a
/// data file element with a single byte sub-element offset, so a file holds at most 256
/// elements (words for N/B/I/O/S/A, 32-bit elements for L/F). Array tags clamp to this.
///
public const int MaxElements = 256;
}
public sealed class AbLegacyProbeOptions
{
/// Gets or sets a value indicating whether connectivity probing is enabled.
public bool Enabled { get; init; } = true;
/// Gets or sets the interval between probe attempts.
public TimeSpan Interval { get; init; } = TimeSpan.FromSeconds(5);
/// Gets or sets the timeout for each probe operation.
public TimeSpan Timeout { get; init; } = TimeSpan.FromSeconds(2);
/// Gets or sets the probe address (defaults to S:0 — status file, first word).
public string? ProbeAddress { get; init; } = "S:0";
}