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 ConveyorLineJob_South : IJob { private readonly TcpSocketServer _TcpSocket; private static readonly ConcurrentDictionary _socketStates = new(); private static int _eventSubscribedFlag = 0; private readonly ITaskService _taskService; private readonly ITaskExecuteDetailService _taskExecuteDetailService; private readonly ITaskRepository _taskRepository; private readonly IRouterService _routerService; public ConveyorLineJob_South( 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); ConveyorLineDevice? device = value as ConveyorLineDevice; 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 { } } /// /// 接收报文更新对应堆垛机 /// /// private async Task _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 _TcpSocket_RobotReceived(string clientId) { _socketStates.TryRemove(clientId, out _); return Task.FromResult(null); } /// /// 下发任务(独立序列号,互不影响) /// 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 ""; } } } }