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