using Quartz;
|
using System.Collections.Concurrent;
|
using System.Data;
|
using System.Net.Sockets;
|
using WIDESEAWCS_Common.TaskEnum;
|
using WIDESEAWCS_Core.Helper;
|
using WIDESEAWCS_ITaskInfoRepository;
|
using WIDESEAWCS_ITaskInfoService;
|
using WIDESEAWCS_Model.Models;
|
using WIDESEAWCS_QuartzJob;
|
using WIDESEAWCS_QuartzJob.Service;
|
using WIDESEAWCS_Tasks.SocketServer;
|
using WIDESEAWCS_Tasks.StackerCraneJob;
|
|
namespace WIDESEAWCS_Tasks
|
{
|
[DisallowConcurrentExecution]
|
public class StackerCraneJob_BTI : IJob
|
{
|
private readonly TcpSocketServer _TcpSocket;
|
private static readonly ConcurrentDictionary<string, StackerSocketState_BTI> _socketStates = new();
|
private static int _eventSubscribedFlag = 0;
|
|
private readonly ITaskService _taskService;
|
private readonly ITaskExecuteDetailService _taskExecuteDetailService;
|
private readonly ITaskRepository _taskRepository;
|
private readonly IRouterService _routerService;
|
|
public StackerCraneJob_BTI(
|
TcpSocketServer TcpSocket,
|
ITaskService taskService,
|
ITaskExecuteDetailService taskExecuteDetailService,
|
ITaskRepository taskRepository,
|
IRouterService routerService)
|
{
|
_TcpSocket = TcpSocket;
|
_taskService = taskService;
|
_taskExecuteDetailService = taskExecuteDetailService;
|
_taskRepository = taskRepository;
|
_routerService = routerService;
|
}
|
|
public async Task Execute(IJobExecutionContext context)
|
{
|
try
|
{
|
bool flag = context.JobDetail.JobDataMap.TryGetValue("JobParams", out object? value);
|
StackerCraneDevice? device = value as StackerCraneDevice;
|
|
if (!flag || device == null || string.IsNullOrEmpty(device.IPAddress))
|
return;
|
|
string ip = device.IPAddress;
|
|
// 获取当前IP的Socket状态
|
StackerSocketState_BTI state = _socketStates.GetOrAdd(ip, _ => new StackerSocketState_BTI { IPAddress = ip });
|
|
// 检查客户端是否在线
|
if (!_TcpSocket.GetClientIds().Contains(ip))
|
return;
|
|
// 全局只订阅一次事件
|
if (Interlocked.CompareExchange(ref _eventSubscribedFlag, 1, 0) == 0)
|
{
|
_TcpSocket.MessageReceivedBTI += _TcpSocket_MessageReceived;
|
_TcpSocket.StackerReceivedBTI += _TcpSocket_RobotReceived;
|
}
|
|
// 启动客户端监听
|
if (!state.IsEventSubscribed)
|
{
|
if (_TcpSocket._clients.TryGetValue(ip, out TcpClient client))
|
{
|
_ = _TcpSocket.HandleClientAsync(client, ip, _TcpSocket._cts.Token, state);
|
state.IsEventSubscribed = true;
|
}
|
}
|
var craneList = CraneManager_BTI.GetOrCreateCraneList(ip);
|
|
// 遍历每一台堆垛机,下发任务(独立执行、互不干扰)
|
foreach (var (craneCode, crane) in craneList)
|
{
|
try
|
{
|
// 正在执行任务的跳过
|
if (crane.CurrentTask != null)
|
continue;
|
|
// 获取该堆垛机的待执行任务
|
Dt_Task? task = _taskService.QueryStackerTask(craneCode, null);
|
if (task == null)
|
continue;
|
|
// 下发任务
|
bool sendOk = SendStackerTask(task, ip, crane);
|
if (sendOk)
|
{
|
crane.CurrentTask = task;
|
task.TaskState = TaskStatusEnum.SC_Waiting.ObjToInt();
|
_taskRepository.UpdateData(task);
|
}
|
}
|
catch
|
{
|
|
}
|
}
|
}
|
catch { }
|
}
|
|
/// <summary>
|
/// 接收报文更新对应堆垛机
|
/// </summary>
|
/// <returns></returns>
|
private async Task<string?> _TcpSocket_MessageReceived(string message, bool isJson, TcpClient client, StackerSocketState_BTI state)
|
{
|
try
|
{
|
string ip = state.IPAddress;
|
var craneList = CraneManager_BTI.GetOrCreateCraneList(ip);
|
string msg = message.Trim().ToUpperInvariant();
|
|
// 识别哪台堆垛机发的
|
string craneCode = GetCraneCodeByMsg(msg);
|
if (string.IsNullOrEmpty(craneCode) || !craneList.TryGetValue(craneCode, out var crane))
|
return null;
|
|
// 更新心跳
|
crane.LastHeartbeat = DateTime.Now;
|
|
// 更新运行模式
|
if (msg.Contains("AUTO")) crane.RunMode = 1;
|
else if (msg.Contains("STOP")) crane.RunMode = 2;
|
else if (msg.Contains("MANUAL")) crane.RunMode = 3;
|
|
// 更新故障
|
crane.ErrorState = msg.Contains("ERR") ? 1 : 0;
|
|
// 更新位置
|
if (msg.Contains("POS"))
|
crane.CurrentPosition = ExtractPos(msg);
|
|
// 任务完成
|
if (msg.Contains("ACP") || msg.Contains("FIN"))
|
{
|
if (crane.CurrentTask != null)
|
{
|
_taskService.StackCraneTaskCompleted(crane.CurrentTask.TaskNum);
|
crane.CurrentTask = null;
|
}
|
}
|
}
|
catch { }
|
|
return null;
|
}
|
|
private Task<string?> _TcpSocket_RobotReceived(string clientId)
|
{
|
_socketStates.TryRemove(clientId, out _);
|
return Task.FromResult<string?>(null);
|
}
|
/// <summary>
|
/// 下发任务(独立序列号,互不影响)
|
/// </summary>
|
private bool SendStackerTask(Dt_Task task, string ip, CraneStacker crane)
|
{
|
try
|
{
|
lock (crane.SeqLock)
|
{
|
string seq = crane.SendSeq.ToString("0000");
|
crane.SendSeq++;
|
if (crane.SendSeq > 9999) crane.SendSeq = 1;
|
|
// 按你的协议拼接报文
|
string message = $"1{seq}{crane.CraneCode}MOVE01ARQ{task.CurrentAddress}{task.NextAddress}{task.TaskNum}";
|
return _TcpSocket.SendToDeviceAsync(ip, message).Result;
|
}
|
}
|
catch
|
{
|
return false;
|
}
|
}
|
|
|
private string GetCraneCodeByMsg(string msg)
|
{
|
if (msg.Contains("CRAN32-01")) return "CRAN32-01";
|
if (msg.Contains("CRAN32-02")) return "CRAN32-03";
|
if (msg.Contains("CRAN32-03")) return "CRAN32-03";
|
return "";
|
}
|
|
private string ExtractPos(string msg)
|
{
|
try
|
{
|
int start = msg.IndexOf("POS=") + 4;
|
int end = msg.IndexOf(" ", start);
|
return end > 0 ? msg.Substring(start, end - start) : msg.Substring(start);
|
}
|
catch { return ""; }
|
}
|
}
|
}
|