using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Driver.FOCAS; using ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Wire; namespace ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests; /// /// #740 / R07:H14 — the capability matrix admits macro numbers up to 99999 (30i/31i/32i) and parameters up /// to 29999 (Unknown: anything), and the FOCAS/2 request block carries 32-bit arguments, but the adapter /// cast every number to short: MACRO:99999 asked the CNC for #-31073 and published /// that variable Good under the authored tag. Numbers now travel as int end to end. /// [Trait("Category", "Unit")] public sealed class FocasWideNumberTests { /// The macro request carries the full number in both 32-bit argument slots. [Theory] [InlineData(500)] [InlineData(32767)] [InlineData(32768)] [InlineData(99999)] public void Macro_request_carries_the_unnarrowed_number(int number) { var block = FocasWireClient.MacroRequest(number, pathId: 1); block.Command.ShouldBe((ushort)0x0015); block.Arg1.ShouldBe(number); block.Arg2.ShouldBe(number); } /// /// Positive control on the wire encoding: the request for #500 is byte-identical to the one the real /// 31i-B answered in the ref-macro-500-0x0015 capture, so widening changed nothing below 32768. /// [Fact] public void Macro_request_for_500_matches_the_live_capture_bytes() { var body = FocasWireProtocol.BuildRequestBody([FocasWireClient.MacroRequest(500, pathId: 1)]); Convert.ToHexString(body).ShouldBe("0001001C0001000100150000 01F4000001F4000000000000000000000000".Replace(" ", "")); } /// A global parameter puts its number in both arguments; an axis parameter puts the axis second. [Theory] [InlineData(6711, (short)0, 6711)] [InlineData(40000, (short)0, 40000)] [InlineData(40000, (short)2, 2)] public void Parameter_request_carries_the_unnarrowed_number(int number, short axis, int expectedArg2) { var block = FocasWireClient.ParameterRequest(number, axis, pathId: 1); block.Command.ShouldBe((ushort)0x000e); block.Arg1.ShouldBe(number); block.Arg2.ShouldBe(expectedArg2); } /// The decoded macro reports the number that was asked for, not a wrapped one. [Fact] public void Parsed_macro_keeps_a_number_above_short_range() { var payload = new byte[] { 0x05, 0xF5, 0xE1, 0x00, 0x00, 0x0A, 0x00, 0x08 }; var m = FocasWireClient.ParseMacro(99999, payload); m.Number.ShouldBe(99999); m.Scaled.ShouldBe(1.0); } /// /// pmc_rdpmcrng addresses are 16-bit on the wire; a PMC number whose slot runs past 65535 is refused /// rather than wrapped onto a different address (Unknown series admits any number). /// [Theory] [InlineData(100, 1, true)] [InlineData(65535, 1, true)] [InlineData(65534, 2, true)] [InlineData(65535, 2, false)] [InlineData(70000, 1, false)] public void Pmc_range_outside_16_bits_is_refused_not_wrapped(int number, int width, bool ok) { WireFocasClient.TryPmcRange(number, width, out var start, out var end).ShouldBe(ok); if (ok) { ((int)start).ShouldBe(number); ((int)end).ShouldBe(number + width - 1); } } }