wanshenmean
2026-03-26 8e42d0c1b7ae36cff2e7c69999117911a4b6f300
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLineTargetAddressSelector.cs
@@ -1,50 +1,121 @@
using WIDESEAWCS_QuartzJob;
using WIDESEAWCS_QuartzJob;
namespace WIDESEAWCS_Tasks
{
    /// <summary>
    /// 输送线设备请求处理器:处理拘束机/插拔钉机上下层请求。
    /// 输送线目标地址选择器 - 处理拘束机/插拔钉机的上下层请求
    /// </summary>
    /// <remarks>
    /// 核心职责:
    /// 1. 处理入库场景的目标地址选择
    /// 2. 处理出库场景的目标地址选择
    /// 3. 判断拘束机和插拔钉机的物料请求状态
    /// 4. 协调输送线与上下层设备之间的物料流转
    ///
    /// 拘束机和插拔钉机都有上下两层结构,
    /// 每层都有独立的物料请求和出料信号,需要分别处理。
    /// </remarks>
    public class ConveyorLineTargetAddressSelector
    {
        /// <summary>
        /// 拘束机名称常量
        /// </summary>
        private const string ConstraintMachineName = "拘束机";
        /// <summary>
        /// 插拔钉机名称常量
        /// </summary>
        private const string PinMachineName = "插拔钉机";
        // 拘束机点位
        /// <summary>
        /// 拘束机对应的点位编码列表
        /// </summary>
        /// <remarks>
        /// 当目标地址在这些编码中时,表示需要与拘束机交互。
        /// </remarks>
        private static readonly List<string> ConstraintMachineCodes = new List<string> { "10180", "20090" };
        // 插拔钉机点位
        /// <summary>
        /// 插拔钉机对应的点位编码列表
        /// </summary>
        /// <remarks>
        /// 当目标地址在这些编码中时,表示需要与插拔钉机交互。
        /// </remarks>
        private static readonly List<string> PinMachineCodes = new List<string> { "10190", "20100" };
        /// <summary>
        /// 处理入库场景的下一地址请求
        /// </summary>
        /// <remarks>
        /// 当入库任务执行到某个位置时调用此方法。
        /// 判断目标设备是否需要物料或可以出料。
        /// </remarks>
        /// <param name="conveyorLine">输送线设备对象</param>
        /// <param name="nextAddress">下一地址/目标设备编码</param>
        /// <param name="childDeviceCode">当前子设备编码</param>
        public void HandleInboundNextAddress(CommonConveyorLine conveyorLine, string nextAddress, string childDeviceCode)
        {
            // 调用通用处理方法,isUpper = true 表示处理上层
            HandleDeviceRequest(conveyorLine, nextAddress, childDeviceCode, isUpper: true);
        }
        /// <summary>
        /// 处理出库场景的下一地址请求
        /// </summary>
        /// <remarks>
        /// 当出库任务执行到某个位置时调用此方法。
        /// 判断目标设备是否需要物料或可以出料。
        /// </remarks>
        /// <param name="conveyorLine">输送线设备对象</param>
        /// <param name="nextAddress">下一地址/目标设备编码</param>
        /// <param name="childDeviceCode">当前子设备编码</param>
        public void HandleOutboundNextAddress(CommonConveyorLine conveyorLine, string nextAddress, string childDeviceCode)
        {
            // 调用通用处理方法,isUpper = false 表示处理下层
            HandleDeviceRequest(conveyorLine, nextAddress, childDeviceCode, isUpper: false);
        }
        /// <summary>
        /// 通用设备请求处理方法
        /// </summary>
        /// <remarks>
        /// 根据目标地址类型(拘束机/插拔钉机)调用相应的处理逻辑。
        /// 处理上下层设备的物料请求和出料协调。
        /// </remarks>
        /// <param name="conveyorLine">输送线设备对象</param>
        /// <param name="nextAddress">下一地址/目标设备编码</param>
        /// <param name="childDeviceCode">当前子设备编码</param>
        /// <param name="isUpper">是否处理上层(true=上层,false=下层)</param>
        private void HandleDeviceRequest(CommonConveyorLine conveyorLine, string nextAddress, string childDeviceCode, bool isUpper)
        {
            // 获取全局设备列表
            var devices = Storage.Devices;
            // 判断目标设备类型
            if (ConstraintMachineCodes.Contains(nextAddress))
            {
                // 拘束机处理分支
                // 查找拘束机设备
                ConstraintMachine? constraint = devices.OfType<ConstraintMachine>().FirstOrDefault(d => d.DeviceName == ConstraintMachineName);
                if (constraint == null)
                {
                    // 未找到拘束机设备,直接返回
                    return;
                }
                // 处理拘束机的请求
                ProcessDeviceRequest(
                    conveyorLine,
                    childDeviceCode,
                    // 获取物料请求标志(上层或下层)
                    getMaterialRequest: () => isUpper
                        ? constraint.GetValue<ConstraintMachineDBName, short>(ConstraintMachineDBName.MaterialRequestUpper) != 0
                        : constraint.GetValue<ConstraintMachineDBName, short>(ConstraintMachineDBName.MaterialRequestLower) != 0,
                    // 获取出料请求标志(上层或下层)
                    getOutputRequest: () => isUpper
                        ? constraint.GetValue<ConstraintMachineDBName, short>(ConstraintMachineDBName.OutputRequestUpper) != 0
                        : constraint.GetValue<ConstraintMachineDBName, short>(ConstraintMachineDBName.OutputRequestLower) != 0,
                    // 设置输出就绪标志(上层或下层)
                    setOutputReady: outputReq =>
                    {
                        if (isUpper)
@@ -59,21 +130,27 @@
            }
            else if (PinMachineCodes.Contains(nextAddress))
            {
                // 插拔钉机处理分支
                // 查找插拔钉机设备
                PinMachine? pinMachine = devices.OfType<PinMachine>().FirstOrDefault(d => d.DeviceName == PinMachineName);
                if (pinMachine == null)
                {
                    return;
                }
                // 处理插拔钉机的请求
                ProcessDeviceRequest(
                    conveyorLine,
                    childDeviceCode,
                    // 获取物料请求标志(上层或下层)
                    getMaterialRequest: () => isUpper
                        ? pinMachine.GetValue<PinMachineDBName, short>(PinMachineDBName.MaterialRequestUpper) != 0
                        : pinMachine.GetValue<PinMachineDBName, short>(PinMachineDBName.MaterialRequestLower) != 0,
                    // 获取出料请求标志(上层或下层)
                    getOutputRequest: () => isUpper
                        ? pinMachine.GetValue<PinMachineDBName, short>(PinMachineDBName.OutputRequestUpper) != 0
                        : pinMachine.GetValue<PinMachineDBName, short>(PinMachineDBName.OutputRequestLower) != 0,
                    // 设置输出就绪标志(上层或下层)
                    setOutputReady: outputReq =>
                    {
                        if (isUpper)
@@ -88,6 +165,19 @@
            }
        }
        /// <summary>
        /// 处理设备请求的核心逻辑
        /// </summary>
        /// <remarks>
        /// 根据物料请求和出料请求的状态:
        /// - 如果有物料请求,设置目标地址并发送 ACK
        /// - 如果有出料请求,设置设备的输出就绪标志
        /// </remarks>
        /// <param name="conveyorLine">输送线设备对象</param>
        /// <param name="childDeviceCode">当前子设备编码</param>
        /// <param name="getMaterialRequest">获取物料请求状态的委托</param>
        /// <param name="getOutputRequest">获取出料请求状态的委托</param>
        /// <param name="setOutputReady">设置输出就绪标志的委托</param>
        private static void ProcessDeviceRequest(
            CommonConveyorLine conveyorLine,
            string childDeviceCode,
@@ -95,19 +185,27 @@
            Func<bool> getOutputRequest,
            Action<bool> setOutputReady)
        {
            // 获取物料请求状态
            bool materialReq = getMaterialRequest();
            // 获取出料请求状态
            bool outputReq = getOutputRequest();
            // 如果设备需要物料
            if (materialReq)
            {
                // 设置目标地址为 1(表示有料进来)
                conveyorLine.SetValue(ConveyorLineDBNameNew.Target, 1, childDeviceCode);
                // 回复 ACK 确认信号
                conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, 1, childDeviceCode);
            }
            else
            {
                // 设备不需要物料,设置输出就绪标志
                // 通知设备可以继续出料
                setOutputReady(outputReq);
            }
        }
    }
}