fix(modbus): surface Int64/UInt64 node DataType (Driver.Modbus-007)

Make MapDataType internal, split the combined Int64/UInt64 arm to return
DriverDataType.Int64 and DriverDataType.UInt64 respectively, and remove
the now-stale Driver.Modbus-007 caveat doc block and inline comment.
Add a Theory covering both cases; full suite 271/271 green.
This commit is contained in:
Joseph Doherty
2026-06-16 05:23:47 -04:00
parent 97c087f2af
commit bd8fee610b
2 changed files with 15 additions and 20 deletions
@@ -1491,30 +1491,13 @@ public sealed class ModbusDriver
/// Map a Modbus logical type to the driver-agnostic <see cref="DriverDataType"/> used
/// by the address-space builder.
/// </summary>
/// <remarks>
/// <para>
/// <b>Driver.Modbus-007 — Int64 / UInt64 surfacing limitation:</b>
/// <see cref="DriverDataType"/> does not yet include an Int64 enum member, so 64-bit
/// Modbus tags currently surface as <see cref="DriverDataType.Int32"/> on the OPC UA
/// address space. The wire codec (<c>DecodeRegister</c> / <c>EncodeRegister</c>) is
/// correct — values round-trip as 64-bit <c>long</c> / <c>ulong</c> through
/// <c>ReadAsync</c> / <c>WriteAsync</c>. Only the variable node's <c>DataType</c>
/// attribute is misreported. Clients that consume the type advertisement will see a
/// type/value mismatch for values outside the 32-bit signed range. Operators
/// configuring <c>I_64</c> / <c>UI_64</c> tags should be aware of this until the
/// tracked <c>DriverDataType.Int64</c> follow-up ships.
/// </para>
/// </remarks>
private static DriverDataType MapDataType(ModbusDataType t) => t switch
internal static DriverDataType MapDataType(ModbusDataType t) => t switch
{
ModbusDataType.Bool or ModbusDataType.BitInRegister => DriverDataType.Boolean,
ModbusDataType.Int16 or ModbusDataType.Int32 => DriverDataType.Int32,
ModbusDataType.UInt16 or ModbusDataType.UInt32 => DriverDataType.Int32,
// Driver.Modbus-007: Int64 / UInt64 currently surface as Int32 because DriverDataType
// has no Int64 member yet. The wire codec preserves the 64-bit value; only the OPC UA
// node's declared DataType is widened. Tracked for a follow-up that adds the enum
// member + node-type advertisement.
ModbusDataType.Int64 or ModbusDataType.UInt64 => DriverDataType.Int32,
ModbusDataType.Int64 => DriverDataType.Int64,
ModbusDataType.UInt64 => DriverDataType.UInt64,
ModbusDataType.Float32 => DriverDataType.Float32,
ModbusDataType.Float64 => DriverDataType.Float64,
ModbusDataType.String => DriverDataType.String,
@@ -1,6 +1,7 @@
using System.Buffers.Binary;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
using ZB.MOM.WW.OtOpcUa.Driver.Modbus;
namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests;
@@ -278,6 +279,17 @@ public sealed class ModbusDataTypeTests
ModbusDriver.DecodeRegister(wire, lo).ShouldBe("eH");
}
// --- MapDataType node DataType advertisement ---
/// <summary>
/// Verifies that 64-bit Modbus types surface the correct DriverDataType (not the stale Int32 fallback).
/// </summary>
[Theory]
[InlineData(ModbusDataType.Int64, DriverDataType.Int64)]
[InlineData(ModbusDataType.UInt64, DriverDataType.UInt64)]
public void MapDataType_64bit_surfaces_correct_DriverDataType(ModbusDataType wire, DriverDataType expected)
=> ModbusDriver.MapDataType(wire).ShouldBe(expected);
// --- BCD (binary-coded decimal, DL205/DL260 default numeric encoding) ---
/// <summary>