98 lines
4.3 KiB
C#
98 lines
4.3 KiB
C#
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus;
|
|
|
|
/// <summary>
|
|
/// Modbus TCP driver configuration. Bound from the driver's <c>DriverConfig</c> JSON at
|
|
/// <c>DriverHost.RegisterAsync</c>. Every register the driver exposes appears in
|
|
/// <see cref="Tags"/>; names become the OPC UA browse name + full reference.
|
|
/// </summary>
|
|
public sealed class ModbusDriverOptions
|
|
{
|
|
public string Host { get; init; } = "127.0.0.1";
|
|
public int Port { get; init; } = 502;
|
|
public byte UnitId { get; init; } = 1;
|
|
public TimeSpan Timeout { get; init; } = TimeSpan.FromSeconds(2);
|
|
|
|
/// <summary>Pre-declared tag map. Modbus has no discovery protocol — the driver returns exactly these.</summary>
|
|
public IReadOnlyList<ModbusTagDefinition> Tags { get; init; } = [];
|
|
|
|
/// <summary>
|
|
/// Background connectivity-probe settings. When <see cref="ModbusProbeOptions.Enabled"/>
|
|
/// is true the driver runs a tick loop that issues a cheap FC03 at register 0 every
|
|
/// <see cref="ModbusProbeOptions.Interval"/> and raises <c>OnHostStatusChanged</c> on
|
|
/// Running ↔ Stopped transitions. The Admin UI / OPC UA clients see the state through
|
|
/// <see cref="IHostConnectivityProbe"/>.
|
|
/// </summary>
|
|
public ModbusProbeOptions Probe { get; init; } = new();
|
|
}
|
|
|
|
public sealed class ModbusProbeOptions
|
|
{
|
|
public bool Enabled { get; init; } = true;
|
|
public TimeSpan Interval { get; init; } = TimeSpan.FromSeconds(5);
|
|
public TimeSpan Timeout { get; init; } = TimeSpan.FromSeconds(2);
|
|
/// <summary>Register to read for the probe. Zero is usually safe; override for PLCs that lock register 0.</summary>
|
|
public ushort ProbeAddress { get; init; } = 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// One Modbus-backed OPC UA variable. Address is zero-based (Modbus spec numbering, not
|
|
/// the documentation's 1-based coil/register conventions). Multi-register types
|
|
/// (Int32/UInt32/Float32 = 2 regs; Int64/UInt64/Float64 = 4 regs) respect the
|
|
/// <see cref="ByteOrder"/> field — real-world PLCs disagree on word ordering.
|
|
/// </summary>
|
|
/// <param name="Name">
|
|
/// Tag name, used for both the OPC UA browse name and the driver's full reference. Must be
|
|
/// unique within the driver.
|
|
/// </param>
|
|
/// <param name="Region">Coils / DiscreteInputs / InputRegisters / HoldingRegisters.</param>
|
|
/// <param name="Address">Zero-based address within the region.</param>
|
|
/// <param name="DataType">
|
|
/// Logical data type. See <see cref="ModbusDataType"/> for the register count each encodes.
|
|
/// </param>
|
|
/// <param name="Writable">When true and Region supports writes (Coils / HoldingRegisters), IWritable routes writes here.</param>
|
|
/// <param name="ByteOrder">Word ordering for multi-register types. Ignored for Bool / Int16 / UInt16 / BitInRegister / String.</param>
|
|
/// <param name="BitIndex">For <c>DataType = BitInRegister</c>: which bit of the holding register (0-15, LSB-first).</param>
|
|
/// <param name="StringLength">For <c>DataType = String</c>: number of ASCII characters (2 per register, rounded up).</param>
|
|
public sealed record ModbusTagDefinition(
|
|
string Name,
|
|
ModbusRegion Region,
|
|
ushort Address,
|
|
ModbusDataType DataType,
|
|
bool Writable = true,
|
|
ModbusByteOrder ByteOrder = ModbusByteOrder.BigEndian,
|
|
byte BitIndex = 0,
|
|
ushort StringLength = 0);
|
|
|
|
public enum ModbusRegion { Coils, DiscreteInputs, InputRegisters, HoldingRegisters }
|
|
|
|
public enum ModbusDataType
|
|
{
|
|
Bool,
|
|
Int16,
|
|
UInt16,
|
|
Int32,
|
|
UInt32,
|
|
Int64,
|
|
UInt64,
|
|
Float32,
|
|
Float64,
|
|
/// <summary>Single bit within a holding register. <see cref="ModbusTagDefinition.BitIndex"/> selects 0-15 LSB-first.</summary>
|
|
BitInRegister,
|
|
/// <summary>ASCII string packed 2 chars per register, <see cref="ModbusTagDefinition.StringLength"/> characters long.</summary>
|
|
String,
|
|
}
|
|
|
|
/// <summary>
|
|
/// Word ordering for multi-register types. Modbus TCP standard is <see cref="BigEndian"/>
|
|
/// (ABCD for 32-bit: high word at the lower address). Many PLCs — Siemens S7, several
|
|
/// Allen-Bradley series, some Modicon families — use <see cref="WordSwap"/> (CDAB), which
|
|
/// keeps bytes big-endian within each register but reverses the word pair(s).
|
|
/// </summary>
|
|
public enum ModbusByteOrder
|
|
{
|
|
BigEndian,
|
|
WordSwap,
|
|
}
|