wanshenmean
9 小时以前 f319fd5d5e5e0332c4c7e209df64c351dfbe6887
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
using Serilog;
using WIDESEAWCS_QuartzJob;
 
namespace WIDESEAWCS_Tasks
{
    /// <summary>
    /// 输送线目标地址选择器
    /// </summary>
    /// <remarks>
    /// </remarks>
    public class ConveyorLineTargetAddressSelector
    {
        /// <summary>
        /// 日志记录器
        /// </summary>
        /// <remarks>
        /// 通过 Microsoft.Extensions.Logging 接口注入,用于结构化日志输出。
        /// </remarks>
        private readonly ILogger _logger;
 
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="logger">日志记录器,由依赖注入容器自动注入</param>
        public ConveyorLineTargetAddressSelector(ILogger logger)
        {
            _logger = logger; // 保存日志记录器实例,供后续方法使用
        }
 
        /// <summary>
        /// 处理入库场景的下一地址请求
        /// </summary>
        /// <remarks>
        /// 入库任务到达某个位置时调用此方法,判断目标设备是否需要物料。
        /// 入库对应上层工位(Layer.Upper),因为物料从上层进入仓库。
        /// </remarks>
        /// <param name="conveyorLine">输送线设备对象,用于写入目标地址和 ACK 信号</param>
        /// <param name="nextAddress">下一地址/目标设备编码,用于识别目标设备类型</param>
        /// <param name="childDeviceCode">当前子设备编码,用于精确定位写入哪个子设备</param>
        public bool HandleInboundNextAddress(CommonConveyorLine conveyorLine, string nextAddress, string childDeviceCode)
        {
            // 记录入库场景的调试日志,包含子设备和目标地址信息
            WriteDebug(conveyorLine, "入库下一地址", childDeviceCode, nextAddress);
 
            var cvState = conveyorLine.GetValue<ConveyorLineDBNameNew, byte>(ConveyorLineDBNameNew.CV_State, nextAddress);
            bool isAvailable = cvState == 2;
            if (isAvailable)
            {
                return conveyorLine.SetValue(ConveyorLineDBNameNew.Target, Convert.ToInt16(nextAddress), childDeviceCode);
            }
            return false;
        }
 
        /// <summary>
        /// 处理出库场景的下一地址请求
        /// </summary>
        /// <remarks>
        /// 出库任务到达某个位置时调用此方法,判断目标设备是否需要出料。
        /// 出库对应下层工位(Layer.Lower),因为物料从下层离开仓库。
        /// </remarks>
        /// <param name="conveyorLine">输送线设备对象,用于写入目标地址和 ACK 信号</param>
        /// <param name="nextAddress">下一地址/目标设备编码,用于识别目标设备类型</param>
        /// <param name="childDeviceCode">当前子设备编码,用于精确定位写入哪个子设备</param>
        public bool HandleOutboundNextAddress(CommonConveyorLine conveyorLine, string nextAddress, string childDeviceCode)
        {
            // 记录出库场景的调试日志,包含子设备和目标地址信息
            WriteDebug(conveyorLine, "出库下一地址", childDeviceCode, nextAddress);
 
            var cvState = conveyorLine.GetValue<ConveyorLineDBNameNew, byte>(ConveyorLineDBNameNew.CV_State, nextAddress);
            bool isAvailable = cvState == 2;
            if (isAvailable)
            {
                return conveyorLine.SetValue(ConveyorLineDBNameNew.Target, Convert.ToInt16(nextAddress), childDeviceCode);
            }
            return false;
        }
        /// <summary>
        /// 写入调试日志(同时输出到两个日志系统)
        /// </summary>
        /// <remarks>
        /// 统一入口点日志格式,同时向 Microsoft.Extensions.Logging 和 QuartzLogger 写入,
        /// 保证日志既能在控制台查看也能在文件中追溯。
        /// </remarks>
        /// <param name="conveyorLine">输送线设备对象,用于获取设备编码写入 QuartzLogger</param>
        /// <param name="scenario">场景描述,如"入库下一地址"或"出库下一地址"</param>
        /// <param name="childDeviceCode">子设备编码</param>
        /// <param name="nextAddress">目标设备编码</param>
        private void WriteDebug(CommonConveyorLine conveyorLine, string scenario, string childDeviceCode, string nextAddress)
        {
            // 写入结构化日志(可被 Serilog 等日志框架捕获)
            QuartzLogHelper.LogDebug(_logger, "Handle{Scenario}:子设备: {ChildDeviceCode},目标地址: {NextAddress}", $"Handle{scenario}:子设备: {childDeviceCode},目标地址: {nextAddress}", conveyorLine.DeviceCode, scenario, childDeviceCode, nextAddress);
        }
    }
}