using System; using System.Collections.Generic; using System.Drawing.Imaging; using System.IO.Ports; using System.Linq; using System.Net.WebSockets; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using AutoMapper; using HslCommunication.WebSocket; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using OfficeOpenXml.FormulaParsing.Excel.Functions.Logical; using OfficeOpenXml.FormulaParsing.Excel.Functions.Math; using Quartz; using SqlSugar; using StackExchange.Profiling.Internal; using WIDESEA_ISerialPortRepository; using WIDESEA_SerialPortRepository; using WIDESEAWCS_Core; using WIDESEAWCS_Core.BaseRepository; using WIDESEAWCS_DTO.SerialPort; using WIDESEAWCS_ITaskInfoService; using WIDESEAWCS_Model.Models; using WIDESEAWCS_QuartzJob; using WIDESEAWCS_QuartzJob.DTO; using WIDESEAWCS_TaskInfoService; using WIDESEAWCS_Tasks.SerialPort; namespace WIDESEAWCS_Tasks { [DisallowConcurrentExecution] public class SerialPortJob : JobBase, IJob,IDisposable { public void Dispose() { GC.SuppressFinalize(this); } public enum CommandType { None = 0, Get = 1,//发信号 Set = 2,//设值 } public enum CommandResult { SetOK = 0,//parseok GetOK = 1,//03 GetError = 2,//04 } private readonly IPutakeRepository _putakeRepository; private readonly IProcessRepository _processRepository; private readonly ITorqueOpRepository _orqueOpRepository; private WebSocketServer _webSocketContext; private readonly IProcessServer _processServer; private readonly IPutakeServer _putakeServer; public SerialPortJob(IPutakeServer putakeServer,IProcessServer processServer, IPutakeRepository putakeRepository, IProcessRepository processRepository, ITorqueOpRepository torqueOpRepository, WebSocketServer webSocketContext) { _putakeRepository = putakeRepository; _processRepository = processRepository; _orqueOpRepository = torqueOpRepository; _webSocketContext = webSocketContext; _processServer = processServer; _putakeServer = putakeServer; } public Task Execute(IJobExecutionContext context) { try { SerialPortDevice serialPortDevice = (SerialPortDevice)context.JobDetail.JobDataMap.Get("JobParams"); if (serialPortDevice != null) { List deviceProDTOs = serialPortDevice.DeviceProDTOs; foreach (var item in deviceProDTOs) { if (item.DeviceProParamName != CommandType.Get.ToString() && item.DeviceProParamName != CommandType.Set.ToString()) { DeviceProtocolDetailDTO? deviceProtocolDetail = serialPortDevice.DeviceProtocolDetailDTOs.FirstOrDefault(x => x.DeviceProParamName == nameof(CommandType) && x.ProtocolDetailType == nameof(CommandType.Set)); if (deviceProtocolDetail != null) { string group = item.DeviceProDataBlock; if (group == "电气" || group == "地沟" || group == "机械") { ProcessElectricTask(group, serialPortDevice, item, deviceProtocolDetail); } item.DeviceProParamName = CommandType.None.ToString(); } } if (CommandType.Get.ToString() == item.DeviceProParamName) { DeviceProtocolDetailDTO? deviceProtocolDetail = serialPortDevice.DeviceProtocolDetailDTOs.FirstOrDefault(x => x.DeviceProParamName == nameof(CommandType) && x.ProtocolDetailType == nameof(CommandType.Get)); //发送设备号 if (deviceProtocolDetail != null) { serialPortDevice.Communicator.Write(item.DeviceChildCode + deviceProtocolDetail.ProtocalDetailValue, "\r");//打开串口时先设值 WriteDebug("写入", item.DeviceChildCode + deviceProtocolDetail.ProtocalDetailValue); } } if (serialPortDevice.Communicator.Buffers.Count > 0) { string? receiveData = serialPortDevice.Communicator.ToString(Encoding.Default); if (!string.IsNullOrEmpty(receiveData)) { Console.WriteLine("serialPortDevice:" + DateTime.Now.ToString("HH:mm:ss.fff") + receiveData); if (item.DeviceProParamName == CommandType.Set.ToString() || item.DeviceProParamName == CommandType.None.ToString()) { DeviceProtocolDetailDTO? deviceProtocolDetail = serialPortDevice.DeviceProtocolDetailDTOs.FirstOrDefault(x => x.DeviceProParamName == nameof(CommandResult) && x.ProtocolDetailType == nameof(CommandResult.SetOK)); //parseok if (deviceProtocolDetail != null && receiveData.Contains(item.DeviceChildCode + deviceProtocolDetail.ProtocalDetailValue)) { item.DeviceProParamName = CommandType.Get.ToString(); } } else if (item.DeviceProParamName == CommandType.Get.ToString()) { DeviceProtocolDetailDTO? deviceProtocolDetail = serialPortDevice.DeviceProtocolDetailDTOs.FirstOrDefault(x => x.DeviceProParamName == nameof(CommandResult) && x.ProtocolDetailType == nameof(CommandResult.GetOK)); //03成功 if (deviceProtocolDetail != null && receiveData.Contains(item.DeviceChildCode + deviceProtocolDetail.ProtocalDetailValue)) { //把这条数据插入op表中 string group = item.DeviceProDataBlock; // 设备所属组别 string devicecode = item.DeviceChildCode;//设备编号 string torqueValue = ExtractTorqueValue(receiveData);//调用转值方法 if (group == "电气" || group == "地沟" || group == "机械") { SaveTorqueOpData(group, devicecode, torqueValue); item.DeviceProParamName = CommandType.None.ToString(); } } DeviceProtocolDetailDTO? deviceProtocolDetail2 = serialPortDevice.DeviceProtocolDetailDTOs.FirstOrDefault(x => x.DeviceProParamName == nameof(CommandResult) && x.ProtocolDetailType == nameof(CommandResult.GetError)); if (deviceProtocolDetail2 != null && receiveData.Contains(item.DeviceChildCode + deviceProtocolDetail2.ProtocalDetailValue)) { item.DeviceProParamName = CommandType.None.ToString(); } } } //建一个对象将其传给前端 //string data = JsonConvert.SerializeObject(serialPortDevice);//这里serialPortDevice是假设有这个对象 //_webSocketContext.PublishAllClientPayload(data); } } } } catch (Exception ex) { WriteError("CommonConveyorLineJob", "test", ex); } WriteDebug("CommonConveyorLineJob", "test"); return Task.CompletedTask; } /// /// 将0004000转为4.0 /// 0004500转为4.5 /// /// /// private string ExtractTorqueValue(string data) { string[] parts = data.Split(','); // 按逗号分割数据 if (parts.Length > 1) // 确保至少有两个部分 { //返回的是一个类似于82407024103,+0005433,0004500,1702485619 string targetValue = parts[1].TrimStart('+'); // 移除前导 '+' if (Regex.IsMatch(targetValue, @"^\d+$")) // 确保是纯数字 { return (double.Parse(targetValue) / 1000.0).ToString("0.###"); // 除以 1000,保留最多 3 位小数 } } return "0.000"; // 解析失败返回 0.000 } /// /// 处理电气任务逻辑,发送扭矩指令到设备 /// /// 任务分组 /// 串口设备 /// 设备信息 /// 设备协议详情 private void ProcessElectricTask(string group, SerialPortDevice serialPortDevice, DeviceProDTO item, DeviceProtocolDetailDTO deviceProtocolDetail) { //获取当前任务号 //IPutakeServer里面的待执行的第一条任务; var take = _putakeRepository.QueryData(x => x.Grouptype == group) .OrderBy(x => x.Dispatchtime) .FirstOrDefault(); var takeid = take?.Njtakeid;//拿到任务号 //调用Getcircuit拿到当前步骤 var process = _processServer.Getcircuit(group, takeid); if (process != null && process.Status) { var list = JsonConvert.SerializeObject(process.Data); var data = JsonConvert.DeserializeObject(list); if (data?.proNow != null) { int setpNum = data.proNow.SetpNum; int sum = data.proNow.TorqueSum; double torqueone = data.proNow.TorqueOne; double torquetwo = data.proNow.TorqueTwo; int onequantity = data.proNow.TorqueOneQuantity; int towquantity = data.proNow.TorqueTwoQuantity; //判断op表中这个值是否有该条任务的数据 var op = _orqueOpRepository.QueryData(x => x.TakeId == takeid && x.GroupOp == group && x.ProcessSte == setpNum); if (op.Any())//判断是否有数据 { //找到了就要对比现在op表中有多少条,是否和工艺表中的目标一致 // 计算第一个扭矩的数量(在 ±1 误差范围内)//Math.Abs(5.2 - 4.5) = 0.7 // 计入 Math.Abs(6.0 - 4.5) = 1.5 不计入 var oponecount = op.Count(x => Math.Abs(x.TorqueSize - torqueone) <= 1); int times = 0; if (op.Count() > onequantity) { times = onequantity;//如果第一条以及满足就移除onequantity数量的数据 } else { times = op.Count();//没有满足就移除当前的数据数据 } for (int i = 0; i < times; i++) { //移除第一次值的影响(以为有可能俩个目标值相近而产生误判) op.RemoveAt(0); //移除 op 列表的 第一个元素(即最早存入的记录) } // 计算第二个扭矩的数量(在 ±1 误差范围内) var optowcount = op.Count(x => Math.Abs(x.TorqueSize - torquetwo) <= 1); sum = oponecount + optowcount; //第一种,第一个扭力值没有扭完 if (oponecount < onequantity && torqueone != 0) { //设值 //var com = item.DeviceChildCode + deviceProtocolDetail.ProtocalDetailValue // .Replace("[setNum]", (torqueone * 1000).ToString().PadLeft(7, '0')) + "\r"; var com = item.DeviceChildCode + deviceProtocolDetail.ProtocalDetailValue .Replace("[setNum]", Math.Round(torqueone * 1000).ToString().PadLeft(7, '0')) + "\r"; //格式化成整数 serialPortDevice.Communicator.Write(com); //WriteDebug("写入", com); } //第二种,第一个值扭完了,第二个没有扭完 if (oponecount == onequantity && optowcount < towquantity && torquetwo != 0) { //设值 var com = item.DeviceChildCode + deviceProtocolDetail.ProtocalDetailValue .Replace("[setNum]", Math.Round(torquetwo * 1000).ToString().PadLeft(7, '0')) + "\r"; serialPortDevice.Communicator.Write(com); } } //这里这个任务第一次执行,op表中肯定是没有数据的,所有第一次就要把工艺表中的值给它 else if(!op.Any()&& torqueone!=0)//防止步骤一中torqueone的值为0导致报错 { //设值 var com = item.DeviceChildCode + deviceProtocolDetail.ProtocalDetailValue .Replace("[setNum]", Math.Round(torqueone * 1000).ToString().PadLeft(7, '0')) + "\r"; serialPortDevice.Communicator.Write(com); } } else { Console.WriteLine("proNow 为空"); } } else { Console.WriteLine($"Getcireit接口错误:{process?.Message}"); } } /// /// 发送扭矩指令到设备 /// /// 串口设备 /// 设备信息 /// 设备协议详情 /// 扭矩值 private void SendTorqueCommand(SerialPortDevice serialPortDevice, DeviceProDTO item, DeviceProtocolDetailDTO deviceProtocolDetail, double torqueValue) { var com = item.DeviceChildCode + deviceProtocolDetail.ProtocalDetailValue .Replace("[setNum]", Math.Round(torqueValue * 1000).ToString().PadLeft(7, '0')) + "\r"; serialPortDevice.Communicator.Write(com); } /// /// 存储扭矩数据到 `op` 表 /// private void SaveTorqueOpData(string group, string devicecode, string torqueValue) { var take = _putakeRepository.QueryData(x => x.Grouptype == group) .OrderBy(x => x.Dispatchtime) .FirstOrDefault(); var takeid = take?.Njtakeid;//拿到任务号 //调用Getcircuit拿到当前步骤 var process = _processServer.Getcircuit(group, takeid); if (process != null && process.Status) { var list = JsonConvert.SerializeObject(process.Data); var dataz = JsonConvert.DeserializeObject(list); if (dataz?.proNow != null) { int setpNum = dataz.proNow.SetpNum; int sum = dataz.proNow.TorqueSum; double torqueone = dataz.proNow.TorqueOne; int onequantity = dataz.proNow.TorqueOneQuantity; int towquantity = dataz.proNow.TorqueTwoQuantity; double torquetwo = dataz.proNow.TorqueTwo; Dt_TorqueOp Addop = new Dt_TorqueOp() { DeviceCode = devicecode, TakeId = takeid, GroupOp = group, ProcessSte = setpNum, TorqueSize = float.TryParse(torqueValue, out float torque) ? torque : 0.0f, // 这里进行字符串到float的转换 CreateDate = DateTime.Now, }; _orqueOpRepository.AddData(Addop); } } } } }