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
using Microsoft.Extensions.Options;
using WIDESEAWCS_S7Simulator.Core.Interfaces;
using WIDESEAWCS_S7Simulator.Core.Protocol;
 
namespace WIDESEAWCS_S7Simulator.Application.Protocol;
 
/// <summary>
/// 输送线设备协议处理器。
/// </summary>
public class WcsLineProtocolHandler : IDeviceProtocolHandler
{
    private readonly MirrorAckProtocolHandler _mirrorAckHandler;
    private readonly ProtocolMonitoringOptions _options;
 
    public WcsLineProtocolHandler(
        MirrorAckProtocolHandler mirrorAckHandler,
        IOptions<ProtocolMonitoringOptions> options)
    {
        _mirrorAckHandler = mirrorAckHandler;
        _options = options.Value;
    }
 
    public string ProtocolName => "WcsLineProtocol";
 
    public bool Process(IMemoryStore memoryStore, ProtocolTemplate template, ProtocolRuntimeState runtimeState)
    {
        var configRules = ResolveConfiguredRules();
        var autoRules = ResolveAutoRulesFromTemplate(template, configRules.Select(x => x.RuleId));
 
        bool changed = false;
        foreach (var rule in configRules.Concat(autoRules))
        {
            var stateKey = $"{ProtocolName}:{rule.RuleId}";
            changed |= _mirrorAckHandler.Process(memoryStore, template, runtimeState, rule, stateKey);
        }
 
        return changed;
    }
 
    private IReadOnlyList<MirrorAckRuleOptions> ResolveConfiguredRules()
    {
        if (_options.WcsLineRuleIds.Count == 0)
        {
            return Array.Empty<MirrorAckRuleOptions>();
        }
 
        return _options.WcsLineRuleIds
            .Where(x => !string.IsNullOrWhiteSpace(x))
            .Distinct(StringComparer.OrdinalIgnoreCase)
            .Select(ruleId => _options.MirrorAckRules.FirstOrDefault(x =>
                string.Equals(x.RuleId, ruleId, StringComparison.OrdinalIgnoreCase)))
            .Where(rule => rule != null)
            .Select(rule => rule!)
            .ToArray();
    }
 
    private static IReadOnlyList<MirrorAckRuleOptions> ResolveAutoRulesFromTemplate(
        ProtocolTemplate template,
        IEnumerable<string> excludedRuleIds)
    {
        var excluded = new HashSet<string>(excludedRuleIds, StringComparer.OrdinalIgnoreCase);
        var keySet = new HashSet<string>(template.Fields.Select(x => x.FieldKey), StringComparer.OrdinalIgnoreCase);
        var wcsAckFields = template.Fields
            .Where(x => x.FieldKey.EndsWith("_WCS_ACK", StringComparison.OrdinalIgnoreCase))
            .Select(x => x.FieldKey)
            .ToArray();
 
        var rules = new List<MirrorAckRuleOptions>();
        foreach (var ackField in wcsAckFields)
        {
            var prefix = ackField[..^"_WCS_ACK".Length];
            var ruleId = $"auto-{prefix}";
            if (excluded.Contains(ruleId))
            {
                continue;
            }
 
            var plcStb = $"{prefix}_PLC_STB";
            if (!keySet.Contains(plcStb))
            {
                continue;
            }
 
            var taskKey = FindFirstExisting(
                keySet,
                $"{prefix}_WCS_TASK_ID",
                $"{prefix}_TaskNo",
                $"{prefix}_TaskNum");
            var targetKey = FindFirstExisting(
                keySet,
                $"{prefix}_WCS_TARGET_ID",
                $"{prefix}_Target");
            var barcodeKey = FindFirstExisting(
                keySet,
                $"{prefix}_Barcode",
                $"{prefix}_PALLET_CODE");
 
            var clearKeys = new List<string>();
            if (!string.IsNullOrWhiteSpace(taskKey)) clearKeys.Add(taskKey);
            if (!string.IsNullOrWhiteSpace(targetKey)) clearKeys.Add(targetKey);
            if (!string.IsNullOrWhiteSpace(barcodeKey)) clearKeys.Add(barcodeKey);
 
            rules.Add(new MirrorAckRuleOptions
            {
                RuleId = ruleId,
                WcsAckFieldKey = ackField,
                PlcStbFieldKey = plcStb,
                WcsTaskIdFieldKey = null,
                PlcTaskIdFieldKey = null,
                WcsTargetIdFieldKey = null,
                PlcTargetIdFieldKey = null,
                ClearFieldKeysOnAck0 = clearKeys,
                ClearFieldKeysOnAck2 = clearKeys
            });
        }
 
        return rules;
    }
 
    private static string? FindFirstExisting(HashSet<string> keySet, params string[] candidates)
    {
        return candidates.FirstOrDefault(keySet.Contains);
    }
}