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)
|
{
|
constraint.SetValue(ConstraintMachineDBName.ConstraintTrayOutputReadyUpper, outputReq ? 1 : 0);
|
}
|
else
|
{
|
constraint.SetValue(ConstraintMachineDBName.ConstraintTrayOutputReadyLower, outputReq ? 1 : 0);
|
}
|
});
|
}
|
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)
|
{
|
pinMachine.SetValue(PinMachineDBName.PlugPinTrayOutputReadyUpper, outputReq ? 1 : 0);
|
}
|
else
|
{
|
pinMachine.SetValue(PinMachineDBName.PlugPinTrayOutputReadyLower, outputReq ? 1 : 0);
|
}
|
});
|
}
|
}
|
|
/// <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,
|
Func<bool> getMaterialRequest,
|
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);
|
}
|
}
|
}
|
}
|