# 堆垛机出库任务 TargetAddress 输送线站台空闲检查 设计文档
## 1. 背景与目标
在 `StackerCraneTaskSelector.TrySelectOutboundTask` 方法中,当前只检查出库站台的 `NextAddress` 是否可用(`IsOutTaskStationAvailable`)。需求:增加对 `TargetAddress` 输送线站台的空闲状态检查。只有当 `TargetAddress` 输送线站台空闲(`CV_State == 2`)时,才认为该出库任务真正可选。
## 2. 设计方案
### 2.1 新增私有方法
在 `StackerCraneTaskSelector` 类中新增方法 `IsTargetAddressConveyorStationAvailable`:
```csharp
///
/// 判断 TargetAddress 输送线站台是否空闲
///
/// 出库任务
/// 站台空闲返回 true,否则返回 false
private bool IsTargetAddressConveyorStationAvailable([NotNull] Dt_Task task)
{
// 确定任务类型
int taskType = task.TaskType == (int)TaskOutboundTypeEnum.OutEmpty
? StackerCraneConst.EmptyPalletTaskType
: task.TaskType;
// 通过路由查找 TargetAddress 对应的设备信息
Dt_Router? router = _routerService.QueryNextRoute(task.Roadway, task.TargetAddress, taskType);
if (router == null)
{
QuartzLogHelper.LogWarn(_logger, "IsTargetAddressConveyorStationAvailable:未找到 TargetAddress 路由信息,TargetAddress: {TargetAddress},任务号: {TaskNum}",
$"IsTargetAddressConveyorStationAvailable:未找到 TargetAddress 路由信息,TargetAddress: {task.TargetAddress}", task.Roadway, task.TargetAddress, task.TaskNum);
return false;
}
// 查找输送线设备
IDevice? device = Storage.Devices.FirstOrDefault(x => x.DeviceCode == router.ChildPosiDeviceCode);
if (device == null)
{
QuartzLogHelper.LogWarn(_logger, "IsTargetAddressConveyorStationAvailable:未找到输送线设备,ChildPosiDeviceCode: {ChildPosiDeviceCode},任务号: {TaskNum}",
$"IsTargetAddressConveyorStationAvailable:未找到输送线设备,ChildPosiDeviceCode: {router.ChildPosiDeviceCode}", task.Roadway, router.ChildPosiDeviceCode, task.TaskNum);
return false;
}
// 转换为输送线设备
CommonConveyorLine conveyorLine = (CommonConveyorLine)device;
// 读取 CV_State,CV_State == 2 表示空闲
byte cvState = conveyorLine.GetValue(ConveyorLineStatus.CV_State, task.TargetAddress);
bool isAvailable = cvState == 2;
QuartzLogHelper.LogInfo(_logger, "IsTargetAddressConveyorStationAvailable:TargetAddress: {TargetAddress},CV_State: {CV_State},是否空闲: {IsAvailable},任务号: {TaskNum}",
$"IsTargetAddressConveyorStationAvailable:TargetAddress: {task.TargetAddress},CV_State: {cvState},是否空闲: {isAvailable}", task.Roadway, task.TargetAddress, cvState, isAvailable, task.TaskNum);
return isAvailable;
}
```
### 2.2 调用点修改
在 `TrySelectOutboundTask` 方法中,在 `return IsOutTaskStationAvailable(taskAfterTransferCheck) ? taskAfterTransferCheck : null;` 之前插入:
```csharp
// 判断 TargetAddress 输送线站台是否空闲
if (!IsTargetAddressConveyorStationAvailable(taskAfterTransferCheck))
{
return null;
}
```
### 2.3 流程图
```
出库任务进入 TrySelectOutboundTask
↓
移库检查(_transferCheck)
↓
是否移库任务?是 → 返回任务
↓(否)
IsOutTaskStationAvailable(NextAddress 出库站台) → 不可用 → 返回 null
↓(可用)
IsTargetAddressConveyorStationAvailable(TargetAddress 输送线站台) → 不可用 → 返回 null
↓(可用,即 CV_State == 2)
返回任务
```
## 3. 涉及的命名空间
新增方法需要 using:
- `WIDESEAWCS_QuartzJob.ConveyorLine.Enum.ConveyorLineStatus`(`ConveyorLineStatus.CV_State` 枚举)
- `WIDESEAWCS_Model.Models.Dt_Router`(路由实体)
- `WIDESEAWCS_Core.Storage`(设备存储)
## 4. 风险与约束
- `CV_State == 2` 表示空闲是业务约定,需与 PLC 侧协议保持一致
- 如设备未连接或协议配置缺失,`GetValue` 会抛出异常,当前设计让异常向上传播,调用方通过 try-catch 兜底