using HslCommunication; using Newtonsoft.Json; using Quartz; using System.Collections.Concurrent; using System.Net.Sockets; using System.Text.Json; using WIDESEAWCS_Common.HttpEnum; using WIDESEAWCS_Core; using WIDESEAWCS_Core.Helper; using WIDESEAWCS_Core.Http; using WIDESEAWCS_DTO.Stock; using WIDESEAWCS_DTO.TaskInfo; using WIDESEAWCS_ITaskInfoRepository; using WIDESEAWCS_ITaskInfoService; using WIDESEAWCS_Model.Models; using WIDESEAWCS_QuartzJob; using WIDESEAWCS_QuartzJob.Service; using WIDESEAWCS_Tasks.SocketServer; namespace WIDESEAWCS_Tasks { [DisallowConcurrentExecution] public class RobotJob : IJob { private readonly TcpSocketServer _TcpSocket; private static readonly ConcurrentDictionary _socketStates = new(); private static int _eventSubscribedFlag; private readonly ITaskService _taskService; private readonly IRobotTaskService _robottaskService; private readonly ITaskExecuteDetailService _taskExecuteDetailService; private readonly ITaskRepository _taskRepository; private readonly IRouterService _routerService; public RobotJob(TcpSocketServer TcpSocket, IRobotTaskService RobottaskService, ITaskService TaskService) { _TcpSocket = TcpSocket; _robottaskService = RobottaskService; this._taskService = TaskService; } public async Task Execute(IJobExecutionContext context) { bool flag = context.JobDetail.JobDataMap.TryGetValue("JobParams", out object? value); RobotCraneDevice robotCrane = (RobotCraneDevice?)value ?? new RobotCraneDevice(); if (!flag || robotCrane.IsNullOrEmpty()) { return; } string ipAddress = robotCrane.IPAddress; // 获取或创建状态 RobotSocketState state = _socketStates.GetOrAdd(ipAddress, _ => new RobotSocketState { IPAddress = ipAddress, RobotCrane = robotCrane }); // 更新设备信息 state.RobotCrane = robotCrane; // 检查是否有该客户端连接 var clientIds = _TcpSocket.GetClientIds(); if (!clientIds.Contains(ipAddress)) { return; } // 订阅一次 message 事件(全局一次) if (Interlocked.CompareExchange(ref _eventSubscribedFlag, 1, 0) == 0) { _TcpSocket.MessageReceived += _TcpSocket_MessageReceived; _TcpSocket.RobotReceived += _TcpSocket_RobotReceived; } if (!state.IsEventSubscribed) { _TcpSocket._clients.TryGetValue(ipAddress, out TcpClient client); Task clientTask = _TcpSocket.HandleClientAsync(client, robotCrane.IPAddress, _TcpSocket._cts.Token, state); state.IsEventSubscribed = true; } // 获取任务并缓存到状态中 Dt_RobotTask? task = GetTask(robotCrane); if (task != null) { state.CurrentTask = task; if (task.RobotTaskTotalNum != 48) { // 处理正在执行的任务 if (state.RobotRunMode == 1 && state.RobotControlMode == 1) { await Task.Delay(1000); if ((state.CurrentAction == "Homed" || state.CurrentAction == "PickFinished" || state.CurrentAction == "PutFinished") && state.OperStatus == "Running") { // TODO 读取线体电池条码,发送取电池指令 if (true) { // 模拟读取条码 state.CellBarcode = new string[] { "CellBarcode1", "CellBarcode2", "CellBarcode3", "CellBarcode4" }; string taskString = $"Pickbattery,{task.RobotSourceAddress}"; // 发送任务指令 bool result = await _TcpSocket.SendToClientAsync(ipAddress, taskString); } } } } } return; } /// /// 事件:客户端断开连接时触发 /// /// /// private Task _TcpSocket_RobotReceived(string clientId) { _socketStates.TryRemove(clientId, out _); return Task.FromResult(null); } /// /// 事件:收到消息时触发 /// /// /// /// /// /// private async Task _TcpSocket_MessageReceived(string message, bool isJson, TcpClient client, RobotSocketState state) { string messageLower = message.ToLowerInvariant(); if (await IsSimpleCommandAsync(messageLower, state)) { return null; } if (IsPrefixCommand(messageLower)) { try { var parts = message.Split(','); if (parts.Length >= 1) { var cmd = parts[0].ToLowerInvariant(); int[] positions = new int[4]; for (int i = 1; i <= 4 && i < parts.Length; i++) { int.TryParse(parts[i], out positions[i - 1]); } if (cmd.StartsWith("pickfinished")) { StockDTO stockDTO = new StockDTO { SourceLineNo = state.CurrentTask?.RobotSourceAddressLineCode, SourcePalletNo = state.CurrentTask?.RobotSourceAddressPalletCode, TargetPalletNo = state.CurrentTask?.RobotTargetAddressPalletCode, TargetLineNo = state.CurrentTask?.RobotTargetAddressLineCode, Details = positions .Where(x => x > 0) .OrderBy(x => x) .Select((x, idx) => new StockDetailDTO { Quantity = state.CurrentTask?.RobotTaskTotalNum ?? 1, Channel = x > 0 ? x : throw new ArgumentOutOfRangeException(nameof(x), "Channel must be positive"), CellBarcode = state.CellBarcode[idx] }) .ToList() }; state.LastPickPositions = positions; var result = await HttpRequestHelper.HTTPPostAsync(nameof(Category.WMS), stockDTO.ToJsonString(), state.CurrentTask?.RobotTaskType == 2 ? nameof(ConfigKey.ChangePalletAsync) : nameof(ConfigKey.SplitPalletAsync)); if (result.Status) { state.CurrentAction = "PickFinished"; } } else if (cmd.StartsWith("putfinished")) { state.LastPutPositions = positions; if (state.CurrentTask?.RobotTaskType == 1) { // 发送数据给WMS组盘/换盘 StockDTO stockDTO = new StockDTO { SourceLineNo = state.CurrentTask?.RobotSourceAddressLineCode, SourcePalletNo = state.CurrentTask?.RobotSourceAddressPalletCode, TargetPalletNo = state.CurrentTask?.RobotTargetAddressPalletCode, TargetLineNo = state.CurrentTask?.RobotTargetAddressLineCode, Details = positions .Where(x => x > 0) .OrderBy(x => x) .Select((x, idx) => new StockDetailDTO { Quantity = state.CurrentTask?.RobotTaskTotalNum ?? 1, Channel = x > 0 ? x : throw new ArgumentOutOfRangeException(nameof(x), "Channel must be positive"), CellBarcode = state.CellBarcode[idx] }) .ToList() }; var result = await HttpRequestHelper.HTTPPostAsync(nameof(Category.WMS), stockDTO.ToJsonString(), nameof(ConfigKey.GroupPalletAsync)); if (result.Status) { state.CurrentAction = "PutFinished"; } } } } } catch { } return null; } return null; } /// /// 机械手简单命令处理 /// /// /// /// private async Task IsSimpleCommandAsync(string message, RobotSocketState state) { switch (message) { case "homing": state.CurrentAction = "Homing"; return true; case "homed": state.CurrentAction = "Homed"; return true; case "picking": state.CurrentAction = "Picking"; return true; case "puting": state.CurrentAction = "Putting"; return true; case "allpickfinished": state.CurrentAction = "AllPickFinished"; if (state.CurrentTask?.RobotTaskType == 2 || state.CurrentTask?.RobotTaskType == 3) { await HandleInboundTaskAsync(state, useSourceAddress: true); } return true; case "allputfinished": state.CurrentAction = "AllPutFinished"; if (state.CurrentTask?.RobotTaskType == 1) { await HandleInboundTaskAsync(state, useSourceAddress: false); } return true; case "running": state.OperStatus = "Running"; return true; case "pausing": state.OperStatus = "Pausing"; return true; case "warming": state.OperStatus = "Warming"; return true; case "emstoping": state.OperStatus = "Emstoping"; return true; case "runmode,1": state.RobotRunMode = 1; return true; case "runmode,2": state.RobotRunMode = 2; return true; case "controlmode,1": state.RobotControlMode = 1; return true; case "controlmode,2": state.RobotControlMode = 2; return true; case "armobject,1": state.RobotArmObject = 1; return true; case "armobject,0": state.RobotArmObject = 0; return true; default: return false; } } private async Task HandleInboundTaskAsync(RobotSocketState state, bool useSourceAddress) { var currentTask = state.CurrentTask; if (currentTask == null) { return; } string roadway = currentTask.RobotRoadway == "1" ? "GWSC001" : currentTask.RobotRoadway == "2" ? "HCSC001" : "SC001"; int warehouseId = currentTask.RobotRoadway == "1" ? 1 : currentTask.RobotRoadway == "2" ? 2 : 3; CreateTaskDto taskDto = new CreateTaskDto { PalletCode = currentTask.RobotTargetAddressPalletCode ?? string.Empty, SourceAddress = currentTask.RobotTargetAddress ?? string.Empty, TargetAddress = currentTask.RobotTargetAddress ?? string.Empty, Roadway = roadway, WarehouseId = warehouseId, PalletType = 1, TaskType = 4 }; var result = await HttpRequestHelper.HTTPPostAsync(nameof(Category.WMS), taskDto.ToJsonString(), nameof(ConfigKey.CreateTaskInboundAsync)); if (!result.Status) { return; } WMSTaskDTO taskDTO = JsonConvert.DeserializeObject(result.Data.ToString() ?? string.Empty) ?? new WMSTaskDTO(); var content = _taskService.ReceiveWMSTask(new List { taskDTO }); if (!content.Status) return; var taskInfo = _taskService.QueryByTaskNum(taskDTO.TaskNum); string targetAddress = useSourceAddress ? taskDTO.SourceAddress : taskDTO.TargetAddress; IDevice? device = Storage.Devices.Where(x => x.DeviceProDTOs.Select(x => x.DeviceChildCode == taskDTO.SourceAddress).FirstOrDefault()).FirstOrDefault() ?? null; device?.Communicator.Write(nameof(ConveyorLineDBNameNew.Target), taskInfo.NextAddress); device?.Communicator.Write(nameof(ConveyorLineDBNameNew.TaskNo), taskDTO.TaskNum); device?.Communicator.Write(nameof(ConveyorLineDBNameNew.WCS_STB), 1); } /// /// 机械手前缀命令处理 /// /// /// private static bool IsPrefixCommand(string message) { return message.StartsWith("pickfinished") || message.StartsWith("putfinished"); } private Dt_RobotTask? GetTask(RobotCraneDevice robotCrane) { return _robottaskService.QueryRobotCraneTask(robotCrane.DeviceCode); } } public class RobotSocketState { public string IPAddress { get; set; } = string.Empty; /// /// 是否已订阅消息事件 /// public bool IsEventSubscribed { get; set; } /// /// 机械手运行模式 /// public int? RobotRunMode { get; set; } /// /// 机械手控制模式 /// public int? RobotControlMode { get; set; } /// /// 机械手抓取对象 /// public int? RobotArmObject { get; set; } /// /// 机械手设备信息 /// public RobotCraneDevice? RobotCrane { get; set; } /// /// 当前动作 /// public string? CurrentAction { get; set; } /// /// 当前状态 /// public string? OperStatus { get; set; } /// /// 取货完成位置 /// public int[]? LastPickPositions { get; set; } /// /// 放货完成位置 /// public int[]? LastPutPositions { get; set; } /// /// 抓取位置条码 /// public string[] CellBarcode { get; set; } /// /// 当前抓取任务 /// public Dt_RobotTask? CurrentTask { get; set; } } }