wanshenmean
2026-03-17 737dec3c384f394fd6f9849b4480b697d1ba35d5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
using WIDESEAWCS_S7Simulator.Application.Protocol;
using WIDESEAWCS_S7Simulator.Core.Entities;
using WIDESEAWCS_S7Simulator.Core.Memory;
using WIDESEAWCS_S7Simulator.Core.Protocol;
 
namespace WIDESEAWCS_S7Simulator.UnitTests.Protocol;
 
public class MirrorAckProtocolHandlerTests
{
    [Fact]
    public void Process_WhenAckIsOne_MirrorsConfiguredFieldsAndResetsStb()
    {
        var memory = BuildMemory();
        var template = BuildTemplate();
        var state = new ProtocolRuntimeState();
        var rule = BuildRule();
        var handler = new MirrorAckProtocolHandler();
 
        memory.Write<byte>("DB1.DBB0", 1);      // WCS 确认位
        memory.Write<int>("DB1.DBD2", 123456);  // WCS 任务号
        memory.Write<short>("DB1.DBW6", 88);    // WCS 目标位
        memory.Write<byte>("DB1.DBB10", 1);     // PLC 状态位
 
        var changed = handler.Process(memory, template, state, rule);
 
        Assert.True(changed);
        Assert.Equal(123456, memory.Read<int>("DB1.DBD20"));
        Assert.Equal((short)88, memory.Read<short>("DB1.DBW24"));
        Assert.Equal((byte)0, memory.Read<byte>("DB1.DBB10"));
    }
 
    [Fact]
    public void Process_WhenAckIsTwo_ClearsConfiguredFields()
    {
        var memory = BuildMemory();
        var template = BuildTemplate();
        var state = new ProtocolRuntimeState();
        var rule = BuildRule();
        var handler = new MirrorAckProtocolHandler();
 
        memory.Write<byte>("DB1.DBB0", 2);      // WCS 确认位
        memory.Write<int>("DB1.DBD20", 1);      // PLC 任务号
        memory.Write<short>("DB1.DBW24", 2);    // PLC 目标位
        memory.Write<byte>("DB1.DBB30", 3);     // 托盘号
        memory.Write<byte>("DB1.DBB10", 1);     // PLC 状态位
 
        var changed = handler.Process(memory, template, state, rule);
 
        Assert.True(changed);
        Assert.Equal(0, memory.Read<int>("DB1.DBD20"));
        Assert.Equal((short)0, memory.Read<short>("DB1.DBW24"));
        Assert.Equal((byte)0, memory.Read<byte>("DB1.DBB30"));
        Assert.Equal((byte)0, memory.Read<byte>("DB1.DBB10"));
    }
 
    [Fact]
    public void Process_不同段状态键_相同Ack也可分别处理()
    {
        var memory = BuildMemory();
        var template = BuildTemplate();
        var state = new ProtocolRuntimeState();
        var rule = BuildRule();
        var handler = new MirrorAckProtocolHandler();
 
        memory.Write<byte>("DB1.DBB0", 1);      // WCS 确认位
        memory.Write<int>("DB1.DBD2", 1001);    // WCS 任务号
        memory.Write<short>("DB1.DBW6", 11);    // WCS 目标位
        memory.Write<byte>("DB1.DBB10", 1);     // PLC 状态位
 
        var changedSeg1 = handler.Process(memory, template, state, rule, "WcsLineProtocol:SEG1");
 
        // 保持 ACK 不变,改写目标值,模拟另一段线体处理。
        memory.Write<int>("DB1.DBD2", 2002);
        memory.Write<short>("DB1.DBW6", 22);
        var changedSeg2 = handler.Process(memory, template, state, rule, "WcsLineProtocol:SEG2");
 
        Assert.True(changedSeg1);
        Assert.True(changedSeg2);
        Assert.Equal(2002, memory.Read<int>("DB1.DBD20"));
        Assert.Equal((short)22, memory.Read<short>("DB1.DBW24"));
    }
 
    private static MemoryStore BuildMemory()
    {
        return new MemoryStore(new MemoryRegionConfig
        {
            DBBlockCount = 2,
            DBBlockSize = 256
        });
    }
 
    private static ProtocolTemplate BuildTemplate()
    {
        return new ProtocolTemplate
        {
            Id = "wcs-line-v1",
            Name = "WCS_LINE_V1",
            Fields = new List<ProtocolFieldMapping>
            {
                new() { FieldKey = "WCS_ACK", DbNumber = 1, Offset = 0, DataType = ProtocolDataType.Byte },
                new() { FieldKey = "WCS_TASK_ID", DbNumber = 1, Offset = 2, DataType = ProtocolDataType.DInt },
                new() { FieldKey = "WCS_TARGET_ID", DbNumber = 1, Offset = 6, DataType = ProtocolDataType.Int },
                new() { FieldKey = "PLC_STB", DbNumber = 1, Offset = 10, DataType = ProtocolDataType.Byte },
                new() { FieldKey = "PLC_TASK_ID", DbNumber = 1, Offset = 20, DataType = ProtocolDataType.DInt },
                new() { FieldKey = "PLC_TARGET_ID", DbNumber = 1, Offset = 24, DataType = ProtocolDataType.Int },
                new() { FieldKey = "PALLET_CODE", DbNumber = 1, Offset = 30, DataType = ProtocolDataType.Byte }
            }
        };
    }
 
    private static MirrorAckRuleOptions BuildRule()
    {
        return new MirrorAckRuleOptions
        {
            RuleId = "line-default",
            WcsAckFieldKey = "WCS_ACK",
            PlcStbFieldKey = "PLC_STB",
            WcsTaskIdFieldKey = "WCS_TASK_ID",
            PlcTaskIdFieldKey = "PLC_TASK_ID",
            WcsTargetIdFieldKey = "WCS_TARGET_ID",
            PlcTargetIdFieldKey = "PLC_TARGET_ID",
            ClearFieldKeysOnAck0 = new List<string> { "PLC_TASK_ID", "PLC_TARGET_ID", "PALLET_CODE" },
            ClearFieldKeysOnAck2 = new List<string> { "PLC_TASK_ID", "PLC_TARGET_ID", "PALLET_CODE" }
        };
    }
}