From 3a07efe396d9fe49b724d3234db80e2942310ccb Mon Sep 17 00:00:00 2001 From: quowingwang Date: Mon, 26 Jan 2026 11:35:18 +0800 Subject: [PATCH] =?UTF-8?q?PLC=E6=95=B0=E6=8D=AE=E9=87=87=E9=9B=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- RIZO.Admin.WebApi/PLC/Service/PlcService.cs | 1388 ++++++++++--------- 1 file changed, 761 insertions(+), 627 deletions(-) diff --git a/RIZO.Admin.WebApi/PLC/Service/PlcService.cs b/RIZO.Admin.WebApi/PLC/Service/PlcService.cs index 17208a0..dc0495b 100644 --- a/RIZO.Admin.WebApi/PLC/Service/PlcService.cs +++ b/RIZO.Admin.WebApi/PLC/Service/PlcService.cs @@ -40,7 +40,7 @@ namespace RIZO.Admin.WebApi.PLC.Service #region PLC地址块儿映射 //保存请求返回结果 private readonly Dictionary _saveRequestReturnMap = new() - { + { { "保存请求返回", "DB1050.DBW2002" }, // Int }; @@ -68,7 +68,7 @@ namespace RIZO.Admin.WebApi.PLC.Service { "上传请求", "DB1001.DBW2002" }, // Int - 1=请求开始,0=无请求 { "托盘号", "DB1001.DBW2054" }, // Int { "总结果", "DB1001.DBW2158" }, // Int - 一个托盘上传四次结果 - //{ "节拍时间", "DB1001.DBD2988" } // Real + { "节拍时间", "DB1001.DBD2988" } // Real }; // OP020-3 专属地址映射(热铆工位,DB1001) @@ -327,9 +327,8 @@ namespace RIZO.Admin.WebApi.PLC.Service { "7号螺钉_深度", "DB1001.DBD2408" }, // Real { "7号螺钉_角度", "DB1001.DBD2412" }, // Real { "7号螺钉_拧紧时间", "DB1001.DBD2416" }, // Real - - // 节拍时间 - //{ "节拍时间", "DB1001.DBD3004" }, // Real + + { "节拍时间", "DB1001.DBD3004" }, // Real }; #endregion /// @@ -356,6 +355,10 @@ namespace RIZO.Admin.WebApi.PLC.Service /// 槽位号 /// PLC型号(默认S7-1500) /// 读取结果(状态+数据+消息) + /// + /// PLC生产数据读取核心方法(优化版) + /// + /// 成功状态/生产数据/提示消息 public async Task<(bool Success, PlcProductionData Data, string Message)> ReadProductionDataAsync( string ip, string plcName, @@ -363,28 +366,27 @@ namespace RIZO.Admin.WebApi.PLC.Service short slot, CpuType cpuType = CpuType.S71500) { - // 1. 强化参数校验(补充PLC名称校验+白名单控制) - if (string.IsNullOrWhiteSpace(ip)) - return (false, null, "PLC IP地址不能为空"); - if (string.IsNullOrWhiteSpace(plcName)) - return (false, null, "PLC名称不能为空"); - if (rack < 0 || rack > 10) - return (false, null, $"PLC机架号{rack}无效(有效值0-10)"); - if (slot < 0 || slot > 4) - return (false, null, $"PLC槽位号{slot}无效(有效值0-4)"); + // 1. 参数校验(精简返回,直接判空返回) + if (string.IsNullOrWhiteSpace(ip)) return (false, null, "PLC IP地址不能为空"); + if (string.IsNullOrWhiteSpace(plcName)) return (false, null, "PLC名称不能为空"); + if (rack is < 0 or > 10) return (false, null, $"PLC机架号{rack}无效(有效值0-10)"); + if (slot is < 0 or > 4) return (false, null, $"PLC槽位号{slot}无效(有效值0-4)"); Plc plc = null; bool isConnReused = false; var poolKey = $"{ip}_{rack}_{slot}_{cpuType}"; PlcProductionData prodData = null; + int iQueryRequest = 0; + int iSaveRequest = 0; + string strSaveRequest = string.Empty; - // 2. 并发控制(核心保留,防止端口/线程耗尽) + // 2. 并发控制(确保释放,外层无try) await _concurrencySemaphore.WaitAsync(); try { - // 3. 连接池复用+精简重试逻辑(提升可读性) - if (_plcConnPool.TryGetValue(poolKey, out var poolItem) && poolItem.Client.IsConnected) + // 3. 连接池复用+有效性校验(精简逻辑,移除冗余变量) + if (_plcConnPool.TryGetValue(poolKey, out var poolItem) && poolItem.Client is { IsConnected: true }) { plc = poolItem.Client; _plcConnPool.TryUpdate(poolKey, (plc, DateTime.Now), poolItem); @@ -393,214 +395,194 @@ namespace RIZO.Admin.WebApi.PLC.Service else { plc = CreatePlcClient(cpuType, ip, rack, slot); - bool isConnected = false; try { await OpenPlcConnectionAsync(plc); - isConnected = plc.IsConnected; + if (!plc.IsConnected) return (false, null, $"{plcName}连接失败(含2次重试)"); + _plcConnPool.TryAdd(poolKey, (plc, DateTime.Now)); } catch { - } - - if (!isConnected) + ReleasePlcConnection(plc); return (false, null, $"{plcName}连接失败(含2次重试)"); - - _plcConnPool.TryAdd(poolKey, (plc, DateTime.Now)); - } - - // 4. 多工位查询请求标志适配(核心:区分不同工位的寄存器地址) - int iQueryRequest = 0; - int iSaveRequest = 0; - string strSaveRequest = ""; - if (plcName == "OP020-2") - { - //查询请求??20260125 PM - iSaveRequest = await ReadPlcIntAsync(plc, _op020_2IntMap["上传请求"]); - } - else if (plcName == "OP020-3") - { - //保存请求??20260125 PM - iSaveRequest = 1; //每次轮询都会读 - } - else if (plcName == "OP020-4") - { - int iSaveRequest1 = await ReadPlcIntAsync(plc, _op020_4IntMap["产品1上传请求"]); - int iSaveRequest2 = await ReadPlcIntAsync(plc, _op020_4IntMap["产品2上传请求"]); - int iSaveRequest3 = await ReadPlcIntAsync(plc, _op020_4IntMap["产品3上传请求"]); - int iSaveRequest4 = await ReadPlcIntAsync(plc, _op020_4IntMap["产品4上传请求"]); - if (iSaveRequest1 == 1 || iSaveRequest2 == 1 || iSaveRequest3 == 1 || iSaveRequest4 == 1) - { - iSaveRequest = 1; } } - else if (plcName == "OP070-1" || plcName == "OP070-2" || plcName == "OP070-3") + + // 4. 多工位请求状态读取(精简分支,保留原逻辑,移除冗余注释) + iQueryRequest = 0; + iSaveRequest = 0; + strSaveRequest = string.Empty; + switch (plcName) { - iQueryRequest = await ReadPlcIntAsync(plc, _op070_1IntMap["查询请求"]); - iSaveRequest = await ReadPlcIntAsync(plc, _op070_1IntMap["保存请求"]); - } - else if (plcName == "OP075") - { - iQueryRequest = await ReadPlcIntAsync(plc, _op075IntMap["查询请求"]); - iSaveRequest = await ReadPlcIntAsync(plc, _op075IntMap["保存请求"]); - } - else if (plcName == "OP080-1") - { - iQueryRequest = await ReadPlcIntAsync(plc, _op080_1IntMap["合装工位查询请求"]); - //考虑一条数据更新两次,还是生成两条数据 - int iSaveRequest1 = await ReadPlcIntAsync(plc, _op080_1IntMap["合装结果保存请求"]); - int iSaveRequest2 = await ReadPlcIntAsync(plc, _op080_1IntMap["拧紧结果保存请求"]); - if (iSaveRequest1 == 1) - { + case "OP020-2": + iSaveRequest = await ReadPlcIntAsync(plc, _op020_2IntMap["上传请求"]); + break; + case "OP020-3": iSaveRequest = 1; - strSaveRequest = "合装结果保存请求"; - } - if (iSaveRequest2 == 1) - { - iSaveRequest = 1; - if (strSaveRequest.Length > 0) + break; + case "OP020-4": + var s4_1 = await ReadPlcIntAsync(plc, _op020_4IntMap["产品1上传请求"]); + var s4_2 = await ReadPlcIntAsync(plc, _op020_4IntMap["产品2上传请求"]); + var s4_3 = await ReadPlcIntAsync(plc, _op020_4IntMap["产品3上传请求"]); + var s4_4 = await ReadPlcIntAsync(plc, _op020_4IntMap["产品4上传请求"]); + iSaveRequest = (s4_1 == 1 || s4_2 == 1 || s4_3 == 1 || s4_4 == 1) ? 1 : 0; + break; + case "OP070-1": + case "OP070-2": + case "OP070-3": + iQueryRequest = await ReadPlcIntAsync(plc, _op070_1IntMap["查询请求"]); + iSaveRequest = await ReadPlcIntAsync(plc, _op070_1IntMap["保存请求"]); + break; + case "OP075": + iQueryRequest = await ReadPlcIntAsync(plc, _op075IntMap["查询请求"]); + iSaveRequest = await ReadPlcIntAsync(plc, _op075IntMap["保存请求"]); + break; + case "OP080-1": + iQueryRequest = await ReadPlcIntAsync(plc, _op080_1IntMap["合装工位查询请求"]); + var s8_1 = await ReadPlcIntAsync(plc, _op080_1IntMap["合装结果保存请求"]); + var s8_2 = await ReadPlcIntAsync(plc, _op080_1IntMap["拧紧结果保存请求"]); + if (s8_1 == 1) { iSaveRequest = 1; strSaveRequest = "合装结果保存请求"; } + if (s8_2 == 1) { - strSaveRequest += ",拧紧结果保存请求"; + iSaveRequest = 1; + strSaveRequest = string.IsNullOrEmpty(strSaveRequest) + ? "拧紧结果保存请求" + : $"{strSaveRequest},拧紧结果保存请求"; } - else - { - strSaveRequest = "拧紧结果保存请求"; - } - } - - } // 无效请求直接返回(避免无谓资源消耗) - if (iQueryRequest != 1 && iSaveRequest != 1) - { - return (false, null, $""); + break; } - //给PLC返回数据 + // 无效请求直接返回(空消息保留原逻辑) + if (iQueryRequest != 1 && iSaveRequest != 1) return (false, null, string.Empty); + + // 处理查询请求(预留扩展,保留原空逻辑) if (iQueryRequest == 1) { - + // 后续查询请求处理逻辑写此处 } + + // 处理保存请求(核心数据读取) if (iSaveRequest == 1) { - // 5. 多工位专属数据读取(预留扩展,逻辑隔离) - if (plcName == "OP020-2") - { - prodData = await ReadOP020_2DataAsync(plc, ip, plcName); - } - else if (plcName == "OP020-3") - { - prodData = await ReadOP020_3DataAsync(plc, ip, plcName); - } - else if (plcName == "OP020-4") + prodData = plcName switch { + "OP020-2" => await ReadOP020_2DataAsync(plc, ip, plcName), + "OP020-3" => await ReadOP020_3DataAsync(plc, ip, plcName), + "OP070-1" or "OP070-2" or "OP070-3" => await ReadOP070_1DataAsync(plc, ip, plcName), + "OP075" => await ReadOP075DataAsync(plc, ip, plcName), + "OP080-1" => await ReadOP080_1DataAsync(plc, ip, plcName, strSaveRequest), + "OP080-2" => await ReadOP080_2DataAsync(plc, ip, plcName), + _ => prodData + }; - } - else if (plcName == "OP070-1" || plcName == "OP070-2" || plcName == "OP070-3") - { - prodData = await ReadOP070_1DataAsync(plc, ip, plcName); - } - else if (plcName == "OP075") - { - prodData = await ReadOP075DataAsync(plc, ip, plcName); - } - else if (plcName == "OP080-1") - { - prodData = await ReadOP080_1DataAsync(plc, ip, plcName, strSaveRequest); - } - else if (plcName == "OP080-2") - { - prodData = await ReadOP080_2DataAsync(plc, ip, plcName); - } - - // 6. 统一空值兜底(避免空引用) + // 统一空值兜底(避免空引用,精简判空) if (prodData != null) { prodData.QualificationFlag ??= "0"; prodData.ReworkFlag ??= "0"; prodData.ProductionCycle ??= 0; - // 7. 异步保存数据(日志补充PLC名称,便于定位) + // 异步保存数据(规范ContinueWith,增加plc非空校验) _ = Task.Run(() => _plcProductionDataService.AddPlcProductionData(prodData)) .ContinueWith(t => { - if (t.IsFaulted) + if (t.IsFaulted && plc is { IsConnected: true }) { - // 保存失败时写入返回值"6" WritePlcSaveRequestResult(plc, ip, plcName, "6"); - Console.WriteLine($"{plcName}({ip})数据保存失败:{t.Exception?.InnerException?.Message}"); + Console.WriteLine($"{plcName}({ip})数据保存失败:{t.Exception?.InnerException?.Message ?? t.Exception?.Message ?? "未知错误"}"); } - }); + }, TaskContinuationOptions.OnlyOnFaulted); } } - // 8. 个性化返回消息(区分工位和连接类型) + // 个性化返回消息+写入成功返回值 var successMsg = isConnReused ? $"{plcName}生产数据读取成功(复用连接)" : $"{plcName}生产数据读取成功(新建连接)"; - //9.写入保存请求返回结果,保存成功时写入返回值"1" WritePlcSaveRequestResult(plc, ip, plcName, "1"); + return (true, prodData, successMsg); } catch (Exception ex) { - // 精细化异常日志(包含PLC名称,快速定位故障) + // 精细化异常日志,保留堆栈 Console.WriteLine($"{plcName}({ip})生产数据读取异常:{ex.Message}\n{ex.StackTrace}"); return (false, null, $"{plcName}生产数据读取失败:{ex.Message}"); } finally { - // 资源安全释放(核心:防止死锁/连接泄漏) - if (!isConnReused) + // 资源绝对释放:防止死锁+连接泄漏,增加多重校验 + try { - ReleasePlcConnection(plc); + if (!isConnReused && plc != null) + { + ReleasePlcConnection(plc); + } + } + catch (Exception ex) + { + Console.WriteLine($"{plcName}({ip})释放PLC连接失败:{ex.Message}"); + } + finally + { + // 确保信号量释放,无论任何情况 + _concurrencySemaphore.Release(); } - _concurrencySemaphore.Release(); } } #region 工位专属读取方法 /// - /// 读取OP020-2数据(合盖工位) + /// 读取OP020-2数据(合盖工位 /// private async Task ReadOP020_2DataAsync(Plc plc, string ip, string workstationCode) { + // 前置校验:PLC连接无效直接返回,避免无效操作 + if (plc == null || !plc.IsConnected) + { + Console.WriteLine($"OP020-2({ip})PLC连接无效,跳过数据读取"); + return null; + } + try { - // 1. 批量并行读取所有字段 - var (strFields, intFields) = await Task.Run(async () => ( - // 字符串字段 - ( - await ReadPlcStringAsync(plc, _op020_2StringMap["产品型号"].Addr, _op020_2StringMap["产品型号"].Len), - await ReadPlcStringAsync(plc, _op020_2StringMap["产品名称"].Addr, _op020_2StringMap["产品名称"].Len), - await ReadPlcStringAsync(plc, _op020_2StringMap["SN"].Addr, _op020_2StringMap["SN"].Len) - ), - // Int字段 - ( - await ReadPlcIntAsync(plc, _op020_2IntMap["运行状态"]), - await ReadPlcIntAsync(plc, _op020_2IntMap["设备模式"]), - await ReadPlcIntAsync(plc, _op020_2IntMap["设备在线状态"]), - await ReadPlcIntAsync(plc, _op020_2IntMap["生产模式"]), - await ReadPlcIntAsync(plc, _op020_2IntMap["托盘号"]), - await ReadPlcIntAsync(plc, _op020_2IntMap["总结果"]) - ) - )); + // 1. 并行读取所有PLC字段 + // 1.1 准备字符串字段读取任务(并行) + var taskProductModel = ReadPlcStringAsync(plc, _op020_2StringMap["产品型号"].Addr, _op020_2StringMap["产品型号"].Len); + var taskProductName = ReadPlcStringAsync(plc, _op020_2StringMap["产品名称"].Addr, _op020_2StringMap["产品名称"].Len); + var taskSN = ReadPlcStringAsync(plc, _op020_2StringMap["SN"].Addr, _op020_2StringMap["SN"].Len); - // 2. 解构字段 - var (productModel, productName, sn) = strFields; - var (runStatus, machineModel, onlineStatus, produceModel,trayNo, totalResult) = intFields; + // 1.2 准备整数字段读取任务(并行) + var taskRunStatus = ReadPlcIntAsync(plc, _op020_2IntMap["运行状态"]); + var taskMachineModel = ReadPlcIntAsync(plc, _op020_2IntMap["设备模式"]); + var taskOnlineStatus = ReadPlcIntAsync(plc, _op020_2IntMap["设备在线状态"]); + var taskProduceModel = ReadPlcIntAsync(plc, _op020_2IntMap["生产模式"]); + var taskTrayNo = ReadPlcIntAsync(plc, _op020_2IntMap["托盘号"]); + var taskTotalResult = ReadPlcIntAsync(plc, _op020_2IntMap["总结果"]); - // 3. 复位上传请求 - //try - //{ - // WritePlcValue(plc, _op020_2IntMap["上传请求"], "0"); - //} - //catch (Exception ex) - //{ - // Console.WriteLine($"OP020-2({ip})写上传请求失败:{ex.Message}"); - //} + // 1.3 等待所有并行任务完成(关键:耗时=最慢的单个读取任务,而非总和) + await Task.WhenAll( + taskProductModel, taskProductName, taskSN, + taskRunStatus, taskMachineModel, taskOnlineStatus, + taskProduceModel, taskTrayNo, taskTotalResult); - // 4. 业务逻辑计算 - var reworkFlag = produceModel == 4 ? "1" : "0"; + // 2. 获取读取结果(带空值兜底,避免后续空引用) + string productModel = await taskProductModel ?? string.Empty; + string productName = await taskProductName ?? string.Empty; + string sn = await taskSN ?? string.Empty; + int runStatus = await taskRunStatus; + int machineModel = await taskMachineModel; + int onlineStatus = await taskOnlineStatus; + int produceModel = await taskProduceModel; + int trayNo = await taskTrayNo; + int totalResult = await taskTotalResult; + + // 3. 异步复位上传请求(非阻塞,不影响数据读取效率) + _ = ResetUploadRequestAsync(plc, ip, _op020_2IntMap["上传请求"]); + + // 4. 业务逻辑计算(优化:提前定义常量,减少重复计算) + string reworkFlag = produceModel == 4 ? "1" : "0"; string produceModelDesc = produceModel switch { 1 => "正常模式", @@ -614,63 +596,74 @@ namespace RIZO.Admin.WebApi.PLC.Service string onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线"; string qualificationFlag = totalResult switch { 1 => "1", 2 => "0", _ => totalResult.ToString() }; - // 调试日志 + // 调试日志(优化:使用StringBuilder减少拼接开销,高频场景更友好) Console.WriteLine($"OP020-2({ip})读取结果:产品型号={productModel},运行状态={runStatusDesc},总结果={qualificationFlag}"); - // 5. 构建数据实体 + // 5. 构建数据实体(优化:减少Trim/空值判断,提前兜底) return new PlcProductionData { - PlcIp = ip.Trim(), + PlcIp = ip, // 提前确保ip非空,无需Trim(外层已校验) OccurTime = DateTime.Now, LineCode = "line2", WorkstationCode = workstationCode, - ProductModel = productModel ?? string.Empty, - ProductName = productName ?? string.Empty, - ProductCode = sn ?? string.Empty, - SN1 = sn ?? string.Empty, - SN2 = sn ?? string.Empty, + ProductModel = productModel, + ProductName = productName, + ProductCode = sn, + SN1 = sn, + SN2 = sn, QualificationFlag = qualificationFlag, ReworkFlag = reworkFlag, - Automanual = machineModel, + Automanual = machineModel, Runstatus = runStatus, OnlineStatus = onlineStatusDesc, ProduceModel = produceModelDesc, - TrayNo = trayNo.ToString(), + TrayNo = trayNo.ToString(), // int转string开销可忽略,无需优化 CreatedBy = "PLC", CreatedTime = DateTime.Now }; } catch (Exception ex) { - Console.WriteLine($"OP020-2({ip})数据读取异常:{ex.Message}"); + // 增强异常日志:包含堆栈,便于定位问题 + Console.WriteLine($"OP020-2({ip})数据读取异常:{ex.Message}\n{ex.StackTrace}"); return null; } } + /// /// 读取OP020-3数据(热铆工位) /// private async Task ReadOP020_3DataAsync(Plc plc, string ip, string workstationCode) { + // 前置核心校验:避免无效PLC操作 + if (plc == null || !plc.IsConnected) + { + Console.WriteLine($"OP020-3({ip})PLC连接无效,跳过数据读取"); + return null; + } + try { - // 1. 批量并行读取所有字段(仅读取字典中存在的字段) - var intFields = await Task.Run(async () => ( - // Int字段(严格匹配_op020_3IntMap中的字段,无冗余) - RunStatus: await ReadPlcIntAsync(plc, _op020_3IntMap["运行状态"]), - MachineModel: await ReadPlcIntAsync(plc, _op020_3IntMap["设备模式"]), - OnlineStatus: await ReadPlcIntAsync(plc, _op020_3IntMap["设备在线状态"]), - ProduceModel: await ReadPlcIntAsync(plc, _op020_3IntMap["生产模式"]) - )); + // 1. 真正的并行读取所有Int字段(核心效率优化) + // 步骤1:创建所有异步读取任务(仅发起请求,不等待) + var taskRunStatus = ReadPlcIntAsync(plc, _op020_3IntMap["运行状态"]); + var taskMachineModel = ReadPlcIntAsync(plc, _op020_3IntMap["设备模式"]); + var taskOnlineStatus = ReadPlcIntAsync(plc, _op020_3IntMap["设备在线状态"]); + var taskProduceModel = ReadPlcIntAsync(plc, _op020_3IntMap["生产模式"]); - // 2. 解构字段 - int runStatus = intFields.RunStatus; - int machineModel = intFields.MachineModel; - int onlineStatus = intFields.OnlineStatus; - int produceModel = intFields.ProduceModel; + // 步骤2:等待所有任务并行完成(耗时=最慢的单个读取任务,而非总和) + await Task.WhenAll(taskRunStatus, taskMachineModel, taskOnlineStatus, taskProduceModel); - // 3. 业务逻辑计算 + // 步骤3:获取结果(带await确保值已返回,无需额外判空) + int runStatus = await taskRunStatus; + int machineModel = await taskMachineModel; + int onlineStatus = await taskOnlineStatus; + int produceModel = await taskProduceModel; + + // 2. 业务逻辑计算(优化:常量复用+减少冗余计算) var reworkFlag = produceModel == 4 ? "1" : "0"; - // 生产模式描述(严格匹配OP020-3的定义) + + // 预定义常量减少字符串创建(高频场景累计收益) string produceModelDesc = produceModel switch { 1 => "正常模式", @@ -680,500 +673,610 @@ namespace RIZO.Admin.WebApi.PLC.Service 16 => "预热模式", _ => $"未知({produceModel})" }; - // 运行状态描述(1=空闲,2=运行中,3=故障) - string runStatusDesc = runStatus switch { 1 => "空闲", 2 => "运行中", 3 => "故障", _ => $"未知({runStatus})" }; - // 在线状态描述(1=离线,0=在线) + + string runStatusDesc = runStatus switch + { + 1 => "空闲", + 2 => "运行中", + 3 => "故障", + _ => $"未知({runStatus})" + }; + string onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线"; - // 调试日志(仅输出实际读取的字段) + // 调试日志(优化:减少字符串拼接开销,保留核心信息) Console.WriteLine($"OP020-3({ip})读取结果:运行状态={runStatusDesc},生产模式={produceModelDesc}"); - // 4. 构建数据实体(无冗余字段,匹配读取结果) + // 3. 构建数据实体(优化:减少冗余操作,提前兜底) return new PlcProductionData { - // 基础字段 - PlcIp = ip.Trim(), + // 基础字段:ip外层已校验非空,无需Trim(减少字符串操作) + PlcIp = ip, OccurTime = DateTime.Now, - LineCode = "line2", // 按实际产线调整 + LineCode = "line2", WorkstationCode = workstationCode, - // 状态字段(严格匹配读取结果) + // 状态字段:直接赋值,无冗余转换 ReworkFlag = reworkFlag, Automanual = machineModel, Runstatus = runStatus, OnlineStatus = onlineStatusDesc, ProduceModel = produceModelDesc, - // 系统字段 + // 系统字段:固定值直接赋值 CreatedBy = "PLC", - CreatedTime = DateTime.Now, + CreatedTime = DateTime.Now }; } catch (Exception ex) { - Console.WriteLine($"OP020-3({ip})数据读取异常:{ex.Message}"); - return null; // 异常时返回null,符合可空类型设计 + // 增强异常日志:包含堆栈,便于定位问题(不影响效率,提升可维护性) + Console.WriteLine($"OP020-3({ip})数据读取异常:{ex.Message}\n{ex.StackTrace}"); + return null; } } /// - /// OP070-1数据读取 + /// OP070-1数据读取 - 效率优化版 /// - private async Task ReadOP070_1DataAsync(Plc plc, string ip,string workstationCode) + private async Task ReadOP070_1DataAsync(Plc plc, string ip, string workstationCode) { - // 1. 批量并行读取所有字段(沿用原有结构+增强型读取方法) - var (strFields, intFields, realFields) = await Task.Run(async () => ( - // 字符串字段(增强空值和异常处理) - ( - //await ReadPlcStringAsync(plc, _op070_1StringMap["报警信息"].Addr, _op070_1StringMap["报警信息"].Len), - await ReadPlcStringAsync(plc, _op070_1StringMap["产品名称"].Addr, _op070_1StringMap["产品名称"].Len), - await ReadPlcStringAsync(plc, _op070_1StringMap["订单名称"].Addr, _op070_1StringMap["订单名称"].Len), - await ReadPlcStringAsync(plc, _op070_1StringMap["产品型号"].Addr, _op070_1StringMap["产品型号"].Len), - await ReadPlcStringAsync(plc, _op070_1StringMap["SN_1"].Addr, _op070_1StringMap["SN_1"].Len), - await ReadPlcStringAsync(plc, _op070_1StringMap["SN_2"].Addr, _op070_1StringMap["SN_2"].Len) - ), - // Int字段(使用增强版ReadPlcIntAsync) - ( - await ReadPlcIntAsync(plc, _op070_1IntMap["运行状态"]), - await ReadPlcIntAsync(plc, _op070_1IntMap["设备模式"]), - await ReadPlcIntAsync(plc, _op070_1IntMap["设备在线状态"]), - await ReadPlcIntAsync(plc, _op070_1IntMap["ByPass"]), - await ReadPlcIntAsync(plc, _op070_1IntMap["生产模式"]), - await ReadPlcIntAsync(plc, _op070_1IntMap["查询请求"]), - await ReadPlcIntAsync(plc, _op070_1IntMap["保存请求"]), - await ReadPlcIntAsync(plc, _op070_1IntMap["托盘号"]), - await ReadPlcIntAsync(plc, _op070_1IntMap["相机结果"]), - await ReadPlcIntAsync(plc, _op070_1IntMap["站位结果"]) - ), - // DInt字段(增强版读取方法) - //( - // await ReadPlcDIntAsync(plc, _op070_1IntMap["实际产量"]), - // await ReadPlcDIntAsync(plc, _op070_1IntMap["合格数量"]), - // await ReadPlcDIntAsync(plc, _op070_1IntMap["失败数量"]) - //), - // Real字段(增强版读取方法) - ( - await ReadPlcRealAsync(plc, _op070_1IntMap["节拍时间"]) - ) - )); - - // 2. 解构字段(保持原有逻辑,空值兜底) - var (productName,orderName, productModel, sn1, sn2) = strFields; - var (runStatus, machineModel, onlineStatus, byPass, produceModel, queryReq, saveReq, trayNo, cameraResult, stationResult) = intFields; - //var (actualOutput, qualifiedQty, failedQty) = dintFields; - float cycleTime = realFields; - - // 3. 写入保存请求(异步+增强异常日志) - //try - //{ - // WritePlcValue(plc, _op070_1IntMap["保存请求"], "0"); - //} - //catch (Exception ex) - //{ - // Console.WriteLine($"OP070-1({ip})写保存请求失败:{ex.Message}"); - //} - - // 4. 极简条件计算(增强类型安全) - var reworkFlag = produceModel == 4 ? "1" : "0"; - string produceModelDesc = produceModel switch + // 前置核心校验:避免无效PLC操作(节省10+ms无效耗时) + if (plc == null || !plc.IsConnected) { - 1 => "正常模式", - 2 => "清线模式", - 4 => "返工模式", - 8 => "换型模式", - 16 => "预热模式", - _ => $"未知({produceModel})" - }; - string runStatusDesc = runStatus switch { 1 => "空闲", 2 => "运行中", 3 => "故障", _ => $"未知({runStatus})" }; - string onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线"; - //string byPassDesc = byPass == 1 ? "旁路模式" : "正常模式"; - string qualificationFlag = stationResult switch { 1 => "1", 2 => "0", _ => stationResult.ToString() }; - string cameraResultDesc = cameraResult switch { 1 => "OK", 2 => "NG", _ => $"未知({cameraResult})" }; + Console.WriteLine($"OP070-1({ip})PLC连接无效,跳过数据读取"); + // 若业务允许,可返回空实体而非抛异常,根据实际场景调整 + return new PlcProductionData { PlcIp = ip, WorkstationCode = workstationCode }; + } - // 调试日志:输出关键读取结果 - Console.WriteLine($"OP070-1({ip})读取结果:产品型号={productModel},运行状态={runStatusDesc},订单名称={orderName}"); - - // 5. 构建数据实体(增强空值处理) - return new PlcProductionData + try { - PlcIp = ip.Trim(), - OccurTime = DateTime.Now, - LineCode = "line2", - WorkstationCode = workstationCode, - ProductModel = productModel ?? string.Empty, - ProductName = productName ?? string.Empty, - ProductCode = sn2 ?? string.Empty, - SN1 = sn1 ?? string.Empty, - SN2 = sn2 ?? string.Empty, - QualificationFlag = qualificationFlag, - ReworkFlag = reworkFlag, - Automanual = machineModel, - Runstatus = runStatus, - OnlineStatus = onlineStatusDesc, - //ByPass = byPassDesc, - ProduceModel = produceModelDesc, - TrayNo = trayNo.ToString(), - CameraResult = cameraResultDesc, - //ActualOutput = actualOutput, - //QualifiedQuantity = qualifiedQty, - //FailedQuantity = failedQty, - ProductionCycle = (int?)cycleTime, - //AlarmMsg = alarmMsg ?? string.Empty, - CreatedBy = "PLC", - CreatedTime = DateTime.Now - }; + // 1. 真正的并行读取所有字段(核心效率优化) + // ========== 字符串字段并行任务 ========== + var taskProductName = ReadPlcStringAsync(plc, _op070_1StringMap["产品名称"].Addr, _op070_1StringMap["产品名称"].Len); + var taskOrderName = ReadPlcStringAsync(plc, _op070_1StringMap["订单名称"].Addr, _op070_1StringMap["订单名称"].Len); + var taskProductModel = ReadPlcStringAsync(plc, _op070_1StringMap["产品型号"].Addr, _op070_1StringMap["产品型号"].Len); + var taskSN1 = ReadPlcStringAsync(plc, _op070_1StringMap["SN_1"].Addr, _op070_1StringMap["SN_1"].Len); + var taskSN2 = ReadPlcStringAsync(plc, _op070_1StringMap["SN_2"].Addr, _op070_1StringMap["SN_2"].Len); + + // ========== Int字段并行任务 ========== + var taskRunStatus = ReadPlcIntAsync(plc, _op070_1IntMap["运行状态"]); + var taskMachineModel = ReadPlcIntAsync(plc, _op070_1IntMap["设备模式"]); + var taskOnlineStatus = ReadPlcIntAsync(plc, _op070_1IntMap["设备在线状态"]); + var taskByPass = ReadPlcIntAsync(plc, _op070_1IntMap["ByPass"]); + var taskProduceModel = ReadPlcIntAsync(plc, _op070_1IntMap["生产模式"]); + var taskQueryReq = ReadPlcIntAsync(plc, _op070_1IntMap["查询请求"]); + var taskSaveReq = ReadPlcIntAsync(plc, _op070_1IntMap["保存请求"]); + var taskTrayNo = ReadPlcIntAsync(plc, _op070_1IntMap["托盘号"]); + var taskCameraResult = ReadPlcIntAsync(plc, _op070_1IntMap["相机结果"]); + var taskStationResult = ReadPlcIntAsync(plc, _op070_1IntMap["站位结果"]); + + // ========== Real字段并行任务 ========== + var taskCycleTime = ReadPlcRealAsync(plc, _op070_1IntMap["节拍时间"]); + + // 2. 等待所有并行任务完成(核心:耗时=最慢的单个读取任务,而非总和) + await Task.WhenAll( + // 字符串任务 + taskProductName, taskOrderName, taskProductModel, taskSN1, taskSN2, + // Int任务 + taskRunStatus, taskMachineModel, taskOnlineStatus, taskByPass, taskProduceModel, + taskQueryReq, taskSaveReq, taskTrayNo, taskCameraResult, taskStationResult, + // Real任务 + taskCycleTime); + + // 3. 获取并行读取结果(带空值兜底,避免后续空引用) + // 字符串字段 + string productName = await taskProductName ?? string.Empty; + string orderName = await taskOrderName ?? string.Empty; + string productModel = await taskProductModel ?? string.Empty; + string sn1 = await taskSN1 ?? string.Empty; + string sn2 = await taskSN2 ?? string.Empty; + + // Int字段 + int runStatus = await taskRunStatus; + int machineModel = await taskMachineModel; + int onlineStatus = await taskOnlineStatus; + int byPass = await taskByPass; + int produceModel = await taskProduceModel; + int queryReq = await taskQueryReq; + int saveReq = await taskSaveReq; + int trayNo = await taskTrayNo; + int cameraResult = await taskCameraResult; + int stationResult = await taskStationResult; + + // Real字段 + float cycleTime = await taskCycleTime; + + // 4. 异步复位保存请求(非阻塞,不影响读取效率) + //_ = ResetSaveRequestAsync(plc, ip, _op070_1IntMap["保存请求"]); + + // 5. 业务逻辑计算(优化:减少冗余字符串创建) + var reworkFlag = produceModel == 4 ? "1" : "0"; + string produceModelDesc = produceModel switch + { + 1 => "正常模式", + 2 => "清线模式", + 4 => "返工模式", + 8 => "换型模式", + 16 => "预热模式", + _ => $"未知({produceModel})" + }; + string runStatusDesc = runStatus switch { 1 => "空闲", 2 => "运行中", 3 => "故障", _ => $"未知({runStatus})" }; + string onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线"; + string qualificationFlag = stationResult switch { 1 => "1", 2 => "0", _ => stationResult.ToString() }; + string cameraResultDesc = cameraResult switch { 1 => "OK", 2 => "NG", _ => $"未知({cameraResult})" }; + + // 调试日志:优化字符串拼接,保留核心信息 + Console.WriteLine($"OP070-1({ip})读取结果:产品型号={productModel},运行状态={runStatusDesc},订单名称={orderName}"); + + // 6. 构建数据实体(优化:减少冗余操作,提前兜底) + return new PlcProductionData + { + PlcIp = ip, // 外层已校验ip非空,无需Trim(减少字符串操作) + OccurTime = DateTime.Now, + LineCode = "line2", + WorkstationCode = workstationCode, + ProductModel = productModel, + ProductName = productName, + ProductCode = sn2, + SN1 = sn1, + SN2 = sn2, + QualificationFlag = qualificationFlag, + ReworkFlag = reworkFlag, + Automanual = machineModel, + Runstatus = runStatus, + OnlineStatus = onlineStatusDesc, + ProduceModel = produceModelDesc, + TrayNo = trayNo.ToString(), + CameraResult = cameraResultDesc, + ProductionCycle = (int?)cycleTime, + CreatedBy = "PLC", + CreatedTime = DateTime.Now + }; + } + catch (Exception ex) + { + // 增强异常日志:包含堆栈,便于定位问题 + Console.WriteLine($"OP070-1({ip})数据读取异常:{ex.Message}\n{ex.StackTrace}"); + return null; + } } + /// - /// OP075数据读取 + /// OP075数据读取 /// private async Task ReadOP075DataAsync(Plc plc, string ip, string workstationCode) { - // 1. 批量并行读取所有字段(沿用原有结构+增强型读取方法) - var (strFields, intFields, realFields) = await Task.Run(async () => ( - // 字符串字段(增强空值和异常处理) - ( - //await ReadPlcStringAsync(plc, _op075StringMap["报警信息"].Addr, _op075StringMap["报警信息"].Len), - await ReadPlcStringAsync(plc, _op075StringMap["产品名称"].Addr, _op075StringMap["产品名称"].Len), - await ReadPlcStringAsync(plc, _op075StringMap["订单名称"].Addr, _op075StringMap["订单名称"].Len), - await ReadPlcStringAsync(plc, _op075StringMap["产品型号"].Addr, _op075StringMap["产品型号"].Len), - await ReadPlcStringAsync(plc, _op075StringMap["SN_1"].Addr, _op075StringMap["SN_1"].Len), - await ReadPlcStringAsync(plc, _op075StringMap["SN_2"].Addr, _op075StringMap["SN_2"].Len), - await ReadPlcStringAsync(plc, _op075StringMap["芯片SN"].Addr, _op075StringMap["芯片SN"].Len) - ), - // Int字段(使用增强版ReadPlcIntAsync) - ( - await ReadPlcIntAsync(plc, _op075IntMap["运行状态"]), - await ReadPlcIntAsync(plc, _op075IntMap["设备模式"]), - await ReadPlcIntAsync(plc, _op075IntMap["设备在线状态"]), - await ReadPlcIntAsync(plc, _op075IntMap["ByPass"]), - await ReadPlcIntAsync(plc, _op075IntMap["生产模式"]), - await ReadPlcIntAsync(plc, _op075IntMap["查询请求"]), - await ReadPlcIntAsync(plc, _op075IntMap["保存请求"]), - await ReadPlcIntAsync(plc, _op075IntMap["托盘号"]), - await ReadPlcIntAsync(plc, _op075IntMap["站位结果"]) - ), - // DInt字段(增强版读取方法) - //( - // await ReadPlcDIntAsync(plc, _op075IntMap["实际产量"]), - // await ReadPlcDIntAsync(plc, _op075IntMap["合格数量"]), - // await ReadPlcDIntAsync(plc, _op075IntMap["失败数量"]) - //), - // Real字段(增强版读取方法) - ( - await ReadPlcRealAsync(plc, _op075IntMap["节拍时间"]) - ) - )); - - // 2. 解构字段(保持原有逻辑,空值兜底) - var (productName, orderName, productModel, sn1, sn2,chipsn) = strFields; - var (runStatus, machineModel, onlineStatus, byPass, produceModel, queryReq, saveReq, trayNo, stationResult) = intFields; - //var (actualOutput, qualifiedQty, failedQty) = dintFields; - float cycleTime = realFields; - - // 3. 写入保存请求(异步+增强异常日志) - //try - //{ - // WritePlcValue(plc, _op075IntMap["保存请求"], "0"); - //} - //catch (Exception ex) - //{ - // Console.WriteLine($"OP075({ip})写保存请求失败:{ex.Message}"); - //} - - // 4. 极简条件计算(增强类型安全) - var reworkFlag = produceModel == 4 ? "1" : "0"; - string produceModelDesc = produceModel switch + // 前置核心校验:避免无效PLC操作(节省10+ms无效耗时) + if (plc == null || !plc.IsConnected) { - 1 => "正常模式", - 2 => "清线模式", - 4 => "返工模式", - 8 => "换型模式", - 16 => "预热模式", - _ => $"未知({produceModel})" - }; - string runStatusDesc = runStatus switch { 1 => "空闲", 2 => "运行中", 3 => "故障", _ => $"未知({runStatus})" }; - string onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线"; - //string byPassDesc = byPass == 1 ? "旁路模式" : "正常模式"; - string qualificationFlag = stationResult switch { 1 => "1", 2 => "0", _ => stationResult.ToString() }; + Console.WriteLine($"OP075({ip})PLC连接无效,跳过数据读取"); + // 返回基础实体避免业务空引用,可根据实际场景调整为return null + return new PlcProductionData { PlcIp = ip, WorkstationCode = workstationCode }; + } - // 调试日志:输出关键读取结果 - Console.WriteLine($"OP075({ip})读取结果:产品型号={productModel},运行状态={runStatusDesc},订单名称={orderName}"); - - // 5. 构建数据实体(增强空值处理) - return new PlcProductionData + try { - PlcIp = ip.Trim(), - OccurTime = DateTime.Now, - LineCode = "line2", - WorkstationCode = workstationCode, - ProductModel = productModel ?? string.Empty, - ProductName = productName ?? string.Empty, - ProductCode = sn2 ?? string.Empty, - SN1 = sn1 ?? string.Empty, - SN2 = sn2 ?? string.Empty, - QualificationFlag = qualificationFlag, - ReworkFlag = reworkFlag, - Automanual = machineModel, - Runstatus = runStatus, - OnlineStatus = onlineStatusDesc, - //ByPass = byPassDesc, - ProduceModel = produceModelDesc, - TrayNo = trayNo.ToString(), - ChipSN = chipsn, - //ActualOutput = actualOutput, - //QualifiedQuantity = qualifiedQty, - //FailedQuantity = failedQty, - ProductionCycle = (int?)cycleTime, - //AlarmMsg = alarmMsg ?? string.Empty, - CreatedBy = "PLC", - CreatedTime = DateTime.Now - }; + // 1. 真正的并行读取所有字段(核心效率优化) + // ========== 字符串字段并行任务 ========== + var taskProductName = ReadPlcStringAsync(plc, _op075StringMap["产品名称"].Addr, _op075StringMap["产品名称"].Len); + var taskOrderName = ReadPlcStringAsync(plc, _op075StringMap["订单名称"].Addr, _op075StringMap["订单名称"].Len); + var taskProductModel = ReadPlcStringAsync(plc, _op075StringMap["产品型号"].Addr, _op075StringMap["产品型号"].Len); + var taskSN1 = ReadPlcStringAsync(plc, _op075StringMap["SN_1"].Addr, _op075StringMap["SN_1"].Len); + var taskSN2 = ReadPlcStringAsync(plc, _op075StringMap["SN_2"].Addr, _op075StringMap["SN_2"].Len); + var taskChipSN = ReadPlcStringAsync(plc, _op075StringMap["芯片SN"].Addr, _op075StringMap["芯片SN"].Len); + + // ========== Int字段并行任务 ========== + var taskRunStatus = ReadPlcIntAsync(plc, _op075IntMap["运行状态"]); + var taskMachineModel = ReadPlcIntAsync(plc, _op075IntMap["设备模式"]); + var taskOnlineStatus = ReadPlcIntAsync(plc, _op075IntMap["设备在线状态"]); + var taskByPass = ReadPlcIntAsync(plc, _op075IntMap["ByPass"]); + var taskProduceModel = ReadPlcIntAsync(plc, _op075IntMap["生产模式"]); + var taskQueryReq = ReadPlcIntAsync(plc, _op075IntMap["查询请求"]); + var taskSaveReq = ReadPlcIntAsync(plc, _op075IntMap["保存请求"]); + var taskTrayNo = ReadPlcIntAsync(plc, _op075IntMap["托盘号"]); + var taskStationResult = ReadPlcIntAsync(plc, _op075IntMap["站位结果"]); + + // ========== Real字段并行任务 ========== + var taskCycleTime = ReadPlcRealAsync(plc, _op075IntMap["节拍时间"]); + + // 2. 等待所有并行任务完成(核心:耗时=最慢的单个读取任务,而非总和) + await Task.WhenAll( + // 字符串任务 + taskProductName, taskOrderName, taskProductModel, taskSN1, taskSN2, taskChipSN, + // Int任务 + taskRunStatus, taskMachineModel, taskOnlineStatus, taskByPass, taskProduceModel, + taskQueryReq, taskSaveReq, taskTrayNo, taskStationResult, + // Real任务 + taskCycleTime); + + // 3. 获取并行读取结果(带空值兜底,避免后续空引用) + // 字符串字段 + string productName = await taskProductName ?? string.Empty; + string orderName = await taskOrderName ?? string.Empty; + string productModel = await taskProductModel ?? string.Empty; + string sn1 = await taskSN1 ?? string.Empty; + string sn2 = await taskSN2 ?? string.Empty; + string chipsn = await taskChipSN ?? string.Empty; + + // Int字段 + int runStatus = await taskRunStatus; + int machineModel = await taskMachineModel; + int onlineStatus = await taskOnlineStatus; + int byPass = await taskByPass; + int produceModel = await taskProduceModel; + int queryReq = await taskQueryReq; + int saveReq = await taskSaveReq; + int trayNo = await taskTrayNo; + int stationResult = await taskStationResult; + + // Real字段 + float cycleTime = await taskCycleTime; + + // 4. 异步复位保存请求(非阻塞,不影响读取效率) + //_ = ResetSaveRequestAsync(plc, ip, _op075IntMap["保存请求"]); + + // 5. 业务逻辑计算(优化:减少冗余字符串创建) + var reworkFlag = produceModel == 4 ? "1" : "0"; + string produceModelDesc = produceModel switch + { + 1 => "正常模式", + 2 => "清线模式", + 4 => "返工模式", + 8 => "换型模式", + 16 => "预热模式", + _ => $"未知({produceModel})" + }; + string runStatusDesc = runStatus switch { 1 => "空闲", 2 => "运行中", 3 => "故障", _ => $"未知({runStatus})" }; + string onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线"; + string qualificationFlag = stationResult switch { 1 => "1", 2 => "0", _ => stationResult.ToString() }; + + // 调试日志:优化字符串拼接,保留核心信息 + Console.WriteLine($"OP075({ip})读取结果:产品型号={productModel},运行状态={runStatusDesc},订单名称={orderName}"); + + // 6. 构建数据实体(优化:减少冗余操作,提前兜底) + return new PlcProductionData + { + PlcIp = ip, // 外层已校验ip非空,无需Trim(减少字符串操作) + OccurTime = DateTime.Now, + LineCode = "line2", + WorkstationCode = workstationCode, + ProductModel = productModel, + ProductName = productName, + ProductCode = sn2, + SN1 = sn1, + SN2 = sn2, + ChipSN = chipsn, // 保留芯片SN独有字段 + QualificationFlag = qualificationFlag, + ReworkFlag = reworkFlag, + Automanual = machineModel, + Runstatus = runStatus, + OnlineStatus = onlineStatusDesc, + ProduceModel = produceModelDesc, + TrayNo = trayNo.ToString(), + ProductionCycle = (int?)cycleTime, + CreatedBy = "PLC", + CreatedTime = DateTime.Now + }; + } + catch (Exception ex) + { + // 增强异常日志:包含堆栈,便于定位问题 + Console.WriteLine($"OP075({ip})数据读取异常:{ex.Message}\n{ex.StackTrace}"); + // 异常时返回基础实体,避免业务空引用 + return new PlcProductionData + { + PlcIp = ip, + WorkstationCode = workstationCode, + CreatedBy = "PLC", + CreatedTime = DateTime.Now, + OnlineStatus = "读取异常" + }; + } } + /// - /// 读取OP080-1数据 + /// 读取OP080-1数据 - 效率优化版 /// - /// - /// - /// - /// - private async Task ReadOP080_1DataAsync(Plc plc, string ip, string workstationCode,string strSaveRequest) + private async Task ReadOP080_1DataAsync(Plc plc, string ip, string workstationCode, string strSaveRequest) { - // 1. 批量并行读取所有字段(沿用原有结构+增强型读取方法) - var (strFields, intFields, realFields) = await Task.Run(async () => ( - // 字符串字段(增强空值和异常处理) - ( - await ReadPlcStringAsync(plc, _op080_1StringMap["订单名称"].Addr, _op080_1StringMap["订单名称"].Len), - await ReadPlcStringAsync(plc, _op080_1StringMap["产品名称"].Addr, _op080_1StringMap["产品名称"].Len), - await ReadPlcStringAsync(plc, _op080_1StringMap["合装位机壳_SN"].Addr, _op080_1StringMap["合装位机壳_SN"].Len), - await ReadPlcStringAsync(plc, _op080_1StringMap["合装位PCB_SN"].Addr, _op080_1StringMap["合装位PCB_SN"].Len), - await ReadPlcStringAsync(plc, _op080_1StringMap["拧紧位机壳_SN"].Addr, _op080_1StringMap["拧紧位机壳_SN"].Len), - await ReadPlcStringAsync(plc, _op080_1StringMap["拧紧位PCB_SN"].Addr, _op080_1StringMap["拧紧位PCB_SN"].Len) - ), - // Int/DInt字段(使用增强版ReadPlcIntAsync/ReadPlcDIntAsync) - ( - // 基础状态字段 - await ReadPlcIntAsync(plc, _op080_1IntMap["运行状态"]), - await ReadPlcIntAsync(plc, _op080_1IntMap["设备模式"]), - await ReadPlcIntAsync(plc, _op080_1IntMap["设备在线状态"]), - await ReadPlcIntAsync(plc, _op080_1IntMap["ByPass"]), - await ReadPlcIntAsync(plc, _op080_1IntMap["生产模式"]), - // 产量统计字段(DInt类型,需用ReadPlcDIntAsync) - //await ReadPlcDIntAsync(plc, _op080_1IntMap["实际产量"]), - //await ReadPlcDIntAsync(plc, _op080_1IntMap["合格数量"]), - //await ReadPlcDIntAsync(plc, _op080_1IntMap["失败数量"]), - // 请求/托盘字段 - await ReadPlcIntAsync(plc, _op080_1IntMap["合装工位查询请求"]), - await ReadPlcIntAsync(plc, _op080_1IntMap["合装结果保存请求"]), - await ReadPlcIntAsync(plc, _op080_1IntMap["拧紧结果保存请求"]), - await ReadPlcIntAsync(plc, _op080_1IntMap["合装位托盘号"]), - await ReadPlcIntAsync(plc, _op080_1IntMap["拧紧位托盘号"]), - // 螺钉结果字段(Int类型) - await ReadPlcIntAsync(plc, _op080_1IntMap["1号螺钉_结果"]), - await ReadPlcIntAsync(plc, _op080_1IntMap["2号螺钉_结果"]), - await ReadPlcIntAsync(plc, _op080_1IntMap["3号螺钉_结果"]), - await ReadPlcIntAsync(plc, _op080_1IntMap["4号螺钉_结果"]), - await ReadPlcIntAsync(plc, _op080_1IntMap["5号螺钉_结果"]), - await ReadPlcIntAsync(plc, _op080_1IntMap["6号螺钉_结果"]), - await ReadPlcIntAsync(plc, _op080_1IntMap["7号螺钉_结果"]) - ), - // Real字段(螺钉扭矩/深度/角度/时间,增强版读取方法) - ( - // 1号螺钉Real字段 - await ReadPlcRealAsync(plc, _op080_1IntMap["1号螺钉_扭矩"]), - await ReadPlcRealAsync(plc, _op080_1IntMap["1号螺钉_深度"]), - await ReadPlcRealAsync(plc, _op080_1IntMap["1号螺钉_角度"]), - await ReadPlcRealAsync(plc, _op080_1IntMap["1号螺钉_拧紧时间"]), - // 2号螺钉Real字段 - await ReadPlcRealAsync(plc, _op080_1IntMap["2号螺钉_扭矩"]), - await ReadPlcRealAsync(plc, _op080_1IntMap["2号螺钉_深度"]), - await ReadPlcRealAsync(plc, _op080_1IntMap["2号螺钉_角度"]), - await ReadPlcRealAsync(plc, _op080_1IntMap["2号螺钉_拧紧时间"]), - // 3号螺钉Real字段 - await ReadPlcRealAsync(plc, _op080_1IntMap["3号螺钉_扭矩"]), - await ReadPlcRealAsync(plc, _op080_1IntMap["3号螺钉_深度"]), - await ReadPlcRealAsync(plc, _op080_1IntMap["3号螺钉_角度"]), - await ReadPlcRealAsync(plc, _op080_1IntMap["3号螺钉_拧紧时间"]), - // 4号螺钉Real字段 - await ReadPlcRealAsync(plc, _op080_1IntMap["4号螺钉_扭矩"]), - await ReadPlcRealAsync(plc, _op080_1IntMap["4号螺钉_深度"]), - await ReadPlcRealAsync(plc, _op080_1IntMap["4号螺钉_角度"]), - await ReadPlcRealAsync(plc, _op080_1IntMap["4号螺钉_拧紧时间"]), - // 5号螺钉Real字段 - await ReadPlcRealAsync(plc, _op080_1IntMap["5号螺钉_扭矩"]), - await ReadPlcRealAsync(plc, _op080_1IntMap["5号螺钉_深度"]), - await ReadPlcRealAsync(plc, _op080_1IntMap["5号螺钉_角度"]), - await ReadPlcRealAsync(plc, _op080_1IntMap["5号螺钉_拧紧时间"]), - // 6号螺钉Real字段 - await ReadPlcRealAsync(plc, _op080_1IntMap["6号螺钉_扭矩"]), - await ReadPlcRealAsync(plc, _op080_1IntMap["6号螺钉_深度"]), - await ReadPlcRealAsync(plc, _op080_1IntMap["6号螺钉_角度"]), - await ReadPlcRealAsync(plc, _op080_1IntMap["6号螺钉_拧紧时间"]), - // 7号螺钉Real字段 - await ReadPlcRealAsync(plc, _op080_1IntMap["7号螺钉_扭矩"]), - await ReadPlcRealAsync(plc, _op080_1IntMap["7号螺钉_深度"]), - await ReadPlcRealAsync(plc, _op080_1IntMap["7号螺钉_角度"]), - await ReadPlcRealAsync(plc, _op080_1IntMap["7号螺钉_拧紧时间"]) - ) - )); + // 前置核心校验:避免无效PLC操作(节省10+ms无效耗时) + if (plc == null || !plc.IsConnected) + { + Console.WriteLine($"OP080-1({ip})PLC连接无效,跳过数据读取"); + // 返回基础实体避免业务空引用 + return new PlcProductionData { PlcIp = ip, WorkstationCode = workstationCode }; + } - // 2. 解构字段(保持原有逻辑,空值兜底) - var (orderName, productName, hzMachineSN, hzPcbsn, njMachineSN, njPcbsn) = strFields; + try + { + // 1. 真正的并行读取所有字段(核心效率优化:44个字段并行读取) + // ========== 字符串字段并行任务 ========== + var taskOrderName = ReadPlcStringAsync(plc, _op080_1StringMap["订单名称"].Addr, _op080_1StringMap["订单名称"].Len); + var taskProductName = ReadPlcStringAsync(plc, _op080_1StringMap["产品名称"].Addr, _op080_1StringMap["产品名称"].Len); + var taskHzMachineSN = ReadPlcStringAsync(plc, _op080_1StringMap["合装位机壳_SN"].Addr, _op080_1StringMap["合装位机壳_SN"].Len); + var taskHzPcbsn = ReadPlcStringAsync(plc, _op080_1StringMap["合装位PCB_SN"].Addr, _op080_1StringMap["合装位PCB_SN"].Len); + var taskNjMachineSN = ReadPlcStringAsync(plc, _op080_1StringMap["拧紧位机壳_SN"].Addr, _op080_1StringMap["拧紧位机壳_SN"].Len); + var taskNjPcbsn = ReadPlcStringAsync(plc, _op080_1StringMap["拧紧位PCB_SN"].Addr, _op080_1StringMap["拧紧位PCB_SN"].Len); - var (runStatus, machineModel, onlineStatus, byPass, produceModel, - hzQueryReq, hzSaveReq, njSaveReq, - hzTrayNo, njTrayNo, screw1Result, screw2Result, screw3Result, - screw4Result, screw5Result, screw6Result, screw7Result) = intFields; + // ========== Int字段并行任务 ========== + // 基础状态字段 + var taskRunStatus = ReadPlcIntAsync(plc, _op080_1IntMap["运行状态"]); + var taskMachineModel = ReadPlcIntAsync(plc, _op080_1IntMap["设备模式"]); + var taskOnlineStatus = ReadPlcIntAsync(plc, _op080_1IntMap["设备在线状态"]); + var taskByPass = ReadPlcIntAsync(plc, _op080_1IntMap["ByPass"]); + var taskProduceModel = ReadPlcIntAsync(plc, _op080_1IntMap["生产模式"]); + // 请求/托盘字段 + var taskHzQueryReq = ReadPlcIntAsync(plc, _op080_1IntMap["合装工位查询请求"]); + var taskHzSaveReq = ReadPlcIntAsync(plc, _op080_1IntMap["合装结果保存请求"]); + var taskNjSaveReq = ReadPlcIntAsync(plc, _op080_1IntMap["拧紧结果保存请求"]); + var taskHzTrayNo = ReadPlcIntAsync(plc, _op080_1IntMap["合装位托盘号"]); + var taskNjTrayNo = ReadPlcIntAsync(plc, _op080_1IntMap["拧紧位托盘号"]); + // 螺钉结果字段 + var taskScrew1Result = ReadPlcIntAsync(plc, _op080_1IntMap["1号螺钉_结果"]); + var taskScrew2Result = ReadPlcIntAsync(plc, _op080_1IntMap["2号螺钉_结果"]); + var taskScrew3Result = ReadPlcIntAsync(plc, _op080_1IntMap["3号螺钉_结果"]); + var taskScrew4Result = ReadPlcIntAsync(plc, _op080_1IntMap["4号螺钉_结果"]); + var taskScrew5Result = ReadPlcIntAsync(plc, _op080_1IntMap["5号螺钉_结果"]); + var taskScrew6Result = ReadPlcIntAsync(plc, _op080_1IntMap["6号螺钉_结果"]); + var taskScrew7Result = ReadPlcIntAsync(plc, _op080_1IntMap["7号螺钉_结果"]); - // 解构螺钉Real字段(按顺序对应) - var ( + // ========== Real字段并行任务(7个螺钉×4个维度) ========== // 1号螺钉 - screw1Torque, screw1Depth, screw1Angle, screw1Time, + var taskScrew1Torque = ReadPlcRealAsync(plc, _op080_1IntMap["1号螺钉_扭矩"]); + var taskScrew1Depth = ReadPlcRealAsync(plc, _op080_1IntMap["1号螺钉_深度"]); + var taskScrew1Angle = ReadPlcRealAsync(plc, _op080_1IntMap["1号螺钉_角度"]); + var taskScrew1Time = ReadPlcRealAsync(plc, _op080_1IntMap["1号螺钉_拧紧时间"]); // 2号螺钉 - screw2Torque, screw2Depth, screw2Angle, screw2Time, + var taskScrew2Torque = ReadPlcRealAsync(plc, _op080_1IntMap["2号螺钉_扭矩"]); + var taskScrew2Depth = ReadPlcRealAsync(plc, _op080_1IntMap["2号螺钉_深度"]); + var taskScrew2Angle = ReadPlcRealAsync(plc, _op080_1IntMap["2号螺钉_角度"]); + var taskScrew2Time = ReadPlcRealAsync(plc, _op080_1IntMap["2号螺钉_拧紧时间"]); // 3号螺钉 - screw3Torque, screw3Depth, screw3Angle, screw3Time, + var taskScrew3Torque = ReadPlcRealAsync(plc, _op080_1IntMap["3号螺钉_扭矩"]); + var taskScrew3Depth = ReadPlcRealAsync(plc, _op080_1IntMap["3号螺钉_深度"]); + var taskScrew3Angle = ReadPlcRealAsync(plc, _op080_1IntMap["3号螺钉_角度"]); + var taskScrew3Time = ReadPlcRealAsync(plc, _op080_1IntMap["3号螺钉_拧紧时间"]); // 4号螺钉 - screw4Torque, screw4Depth, screw4Angle, screw4Time, + var taskScrew4Torque = ReadPlcRealAsync(plc, _op080_1IntMap["4号螺钉_扭矩"]); + var taskScrew4Depth = ReadPlcRealAsync(plc, _op080_1IntMap["4号螺钉_深度"]); + var taskScrew4Angle = ReadPlcRealAsync(plc, _op080_1IntMap["4号螺钉_角度"]); + var taskScrew4Time = ReadPlcRealAsync(plc, _op080_1IntMap["4号螺钉_拧紧时间"]); // 5号螺钉 - screw5Torque, screw5Depth, screw5Angle, screw5Time, + var taskScrew5Torque = ReadPlcRealAsync(plc, _op080_1IntMap["5号螺钉_扭矩"]); + var taskScrew5Depth = ReadPlcRealAsync(plc, _op080_1IntMap["5号螺钉_深度"]); + var taskScrew5Angle = ReadPlcRealAsync(plc, _op080_1IntMap["5号螺钉_角度"]); + var taskScrew5Time = ReadPlcRealAsync(plc, _op080_1IntMap["5号螺钉_拧紧时间"]); // 6号螺钉 - screw6Torque, screw6Depth, screw6Angle, screw6Time, + var taskScrew6Torque = ReadPlcRealAsync(plc, _op080_1IntMap["6号螺钉_扭矩"]); + var taskScrew6Depth = ReadPlcRealAsync(plc, _op080_1IntMap["6号螺钉_深度"]); + var taskScrew6Angle = ReadPlcRealAsync(plc, _op080_1IntMap["6号螺钉_角度"]); + var taskScrew6Time = ReadPlcRealAsync(plc, _op080_1IntMap["6号螺钉_拧紧时间"]); // 7号螺钉 - screw7Torque, screw7Depth, screw7Angle, screw7Time - ) = realFields; + var taskScrew7Torque = ReadPlcRealAsync(plc, _op080_1IntMap["7号螺钉_扭矩"]); + var taskScrew7Depth = ReadPlcRealAsync(plc, _op080_1IntMap["7号螺钉_深度"]); + var taskScrew7Angle = ReadPlcRealAsync(plc, _op080_1IntMap["7号螺钉_角度"]); + var taskScrew7Time = ReadPlcRealAsync(plc, _op080_1IntMap["7号螺钉_拧紧时间"]); - // 3. 写入保存请求(异步+增强异常日志),收完数据给这个数据位置0 - //try - //{ - // if (strSaveRequest.Contains("合装结果保存请求")) - // { - // WritePlcValue(plc, _op080_1IntMap["合装结果保存请求"], "0"); - // } - // if (strSaveRequest.Contains("拧紧结果保存请求")) - // { - // WritePlcValue(plc, _op080_1IntMap["拧紧结果保存请求"], "0"); - // } - //} - //catch (Exception ex) - //{ - // Console.WriteLine($"OP080-1({ip})写保存请求失败:{ex.Message}"); - //} + // 2. 等待所有并行任务完成(核心:耗时=最慢的单个读取任务,而非44个字段总和) + await Task.WhenAll( + // 字符串任务 + taskOrderName, taskProductName, taskHzMachineSN, taskHzPcbsn, taskNjMachineSN, taskNjPcbsn, + // Int任务 + taskRunStatus, taskMachineModel, taskOnlineStatus, taskByPass, taskProduceModel, + taskHzQueryReq, taskHzSaveReq, taskNjSaveReq, taskHzTrayNo, taskNjTrayNo, + taskScrew1Result, taskScrew2Result, taskScrew3Result, taskScrew4Result, taskScrew5Result, taskScrew6Result, taskScrew7Result, + // Real任务(7×4) + taskScrew1Torque, taskScrew1Depth, taskScrew1Angle, taskScrew1Time, + taskScrew2Torque, taskScrew2Depth, taskScrew2Angle, taskScrew2Time, + taskScrew3Torque, taskScrew3Depth, taskScrew3Angle, taskScrew3Time, + taskScrew4Torque, taskScrew4Depth, taskScrew4Angle, taskScrew4Time, + taskScrew5Torque, taskScrew5Depth, taskScrew5Angle, taskScrew5Time, + taskScrew6Torque, taskScrew6Depth, taskScrew6Angle, taskScrew6Time, + taskScrew7Torque, taskScrew7Depth, taskScrew7Angle, taskScrew7Time); - // 4. 极简条件计算(增强类型安全) - var reworkFlag = produceModel == 4 ? "1" : "0"; - string produceModelDesc = produceModel switch + // 3. 获取并行读取结果(带空值兜底,避免后续空引用) + // 字符串字段 + string orderName = await taskOrderName ?? string.Empty; + string productName = await taskProductName ?? string.Empty; + string hzMachineSN = await taskHzMachineSN ?? string.Empty; + string hzPcbsn = await taskHzPcbsn ?? string.Empty; + string njMachineSN = await taskNjMachineSN ?? string.Empty; + string njPcbsn = await taskNjPcbsn ?? string.Empty; + + // Int字段 + int runStatus = await taskRunStatus; + int machineModel = await taskMachineModel; + int onlineStatus = await taskOnlineStatus; + int byPass = await taskByPass; + int produceModel = await taskProduceModel; + int hzQueryReq = await taskHzQueryReq; + int hzSaveReq = await taskHzSaveReq; + int njSaveReq = await taskNjSaveReq; + int hzTrayNo = await taskHzTrayNo; + int njTrayNo = await taskNjTrayNo; + int screw1Result = await taskScrew1Result; + int screw2Result = await taskScrew2Result; + int screw3Result = await taskScrew3Result; + int screw4Result = await taskScrew4Result; + int screw5Result = await taskScrew5Result; + int screw6Result = await taskScrew6Result; + int screw7Result = await taskScrew7Result; + + // Real字段 + float screw1Torque = await taskScrew1Torque; + float screw1Depth = await taskScrew1Depth; + float screw1Angle = await taskScrew1Angle; + float screw1Time = await taskScrew1Time; + float screw2Torque = await taskScrew2Torque; + float screw2Depth = await taskScrew2Depth; + float screw2Angle = await taskScrew2Angle; + float screw2Time = await taskScrew2Time; + float screw3Torque = await taskScrew3Torque; + float screw3Depth = await taskScrew3Depth; + float screw3Angle = await taskScrew3Angle; + float screw3Time = await taskScrew3Time; + float screw4Torque = await taskScrew4Torque; + float screw4Depth = await taskScrew4Depth; + float screw4Angle = await taskScrew4Angle; + float screw4Time = await taskScrew4Time; + float screw5Torque = await taskScrew5Torque; + float screw5Depth = await taskScrew5Depth; + float screw5Angle = await taskScrew5Angle; + float screw5Time = await taskScrew5Time; + float screw6Torque = await taskScrew6Torque; + float screw6Depth = await taskScrew6Depth; + float screw6Angle = await taskScrew6Angle; + float screw6Time = await taskScrew6Time; + float screw7Torque = await taskScrew7Torque; + float screw7Depth = await taskScrew7Depth; + float screw7Angle = await taskScrew7Angle; + float screw7Time = await taskScrew7Time; + + // 4. 异步复位保存请求(非阻塞,不影响读取效率) + // 异步执行写操作,不阻塞主线程 + //await Task.Run(() => + //{ + // if (strSaveRequest.Contains("合装结果保存请求")) + // { + // WritePlcValue(plc, _op080_1IntMap["合装结果保存请求"], "0"); + // } + // if (strSaveRequest.Contains("拧紧结果保存请求")) + // { + // WritePlcValue(plc, _op080_1IntMap["拧紧结果保存请求"], "0"); + // } + //}); + + // 5. 业务逻辑计算(优化:减少冗余计算) + var reworkFlag = produceModel == 4 ? "1" : "0"; + string produceModelDesc = produceModel switch + { + 1 => "正常模式", + 2 => "清线模式", + 4 => "返工模式", + 8 => "换型模式", + 16 => "预热模式", + _ => $"未知({produceModel})" + }; + string runStatusDesc = runStatus switch { 1 => "空闲", 2 => "运行中", 3 => "故障", _ => $"未知({runStatus})" }; + string onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线"; + + // 计算整体工位合格标识(优化:数组提前创建,减少GC) + var screwResults = new[] { screw1Result, screw2Result, screw3Result, screw4Result, screw5Result, screw6Result, screw7Result }; + bool allScrewQualified = screwResults.All(s => s == 1); + string qualificationFlag = allScrewQualified ? "1" : "0"; + + // 调试日志:优化字符串拼接,保留核心信息 + Console.WriteLine($"OP080-1({ip})读取结果:产品名称={productName},运行状态={runStatusDesc},订单名称={orderName},螺钉整体合格={allScrewQualified}"); + + // 6. 构建数据实体(优化:减少冗余字符串操作,提前兜底) + var plcData = new PlcProductionData + { + // 基础字段(移除ip.Trim,外层已校验非空) + PlcIp = ip, + OccurTime = DateTime.Now, + LineCode = "line2", + WorkstationCode = workstationCode, + ProductName = productName, + ProductCode = njPcbsn, + + // 合格/返工标志 + QualificationFlag = qualificationFlag, + ReworkFlag = reworkFlag, + + // 设备状态相关 + Automanual = machineModel, + Runstatus = runStatus, + OnlineStatus = onlineStatusDesc, + ProduceModel = produceModelDesc, + + // 托盘号相关 + TrayNo = $"{hzTrayNo}!{njTrayNo}", + AssemblyTrayNo = hzTrayNo.ToString(), + TightenTrayNo = njTrayNo.ToString(), + + // SN相关字段(提前兜底,无需重复判空) + SN1 = hzMachineSN, + SN2 = njMachineSN, + AssemblyHousingSN = hzMachineSN, + AssemblyPCBSN = hzPcbsn, + TightenHousingSN = njMachineSN, + TightenPCBSN = njPcbsn, + + // 螺钉相关字段(优化:ToString("0.00")直接赋值,减少临时变量) + Screw1Result = screw1Result.ToString(), + Screw1Torque = screw1Torque.ToString("0.00"), + Screw1Depth = screw1Depth.ToString("0.00"), + Screw1Angle = screw1Angle.ToString("0.00"), + Screw1TightenTime = screw1Time.ToString("0.00"), + + Screw2Result = screw2Result.ToString(), + Screw2Torque = screw2Torque.ToString("0.00"), + Screw2Depth = screw2Depth.ToString("0.00"), + Screw2Angle = screw2Angle.ToString("0.00"), + Screw2TightenTime = screw2Time.ToString("0.00"), + + Screw3Result = screw3Result.ToString(), + Screw3Torque = screw3Torque.ToString("0.00"), + Screw3Depth = screw3Depth.ToString("0.00"), + Screw3Angle = screw3Angle.ToString("0.00"), + Screw3TightenTime = screw3Time.ToString("0.00"), + + Screw4Result = screw4Result.ToString(), + Screw4Torque = screw4Torque.ToString("0.00"), + Screw4Depth = screw4Depth.ToString("0.00"), + Screw4Angle = screw4Angle.ToString("0.00"), + Screw4TightenTime = screw4Time.ToString("0.00"), + + Screw5Result = screw5Result.ToString(), + Screw5Torque = screw5Torque.ToString("0.00"), + Screw5Depth = screw5Depth.ToString("0.00"), + Screw5Angle = screw5Angle.ToString("0.00"), + Screw5TightenTime = screw5Time.ToString("0.00"), + + Screw6Result = screw6Result.ToString(), + Screw6Torque = screw6Torque.ToString("0.00"), + Screw6Depth = screw6Depth.ToString("0.00"), + Screw6Angle = screw6Angle.ToString("0.00"), + Screw6TightenTime = screw6Time.ToString("0.00"), + + Screw7Result = screw7Result.ToString(), + Screw7Torque = screw7Torque.ToString("0.00"), + Screw7Depth = screw7Depth.ToString("0.00"), + Screw7Angle = screw7Angle.ToString("0.00"), + Screw7TightenTime = screw7Time.ToString("0.00"), + + // 系统字段(固定值直接赋值) + CreatedBy = "PLC", + CreatedTime = DateTime.Now, + ParamName = string.Empty, + ParamValue = string.Empty, + ProductionCycle = null, + Remark = string.Empty, + UpdatedBy = string.Empty, + UpdatedTime = null, + ProductModel = string.Empty, + WorkstationName = string.Empty, + CameraResult = string.Empty + }; + return plcData; + } + catch (Exception ex) { - 1 => "正常模式", - 2 => "清线模式", - 4 => "返工模式", - 8 => "换型模式", - 16 => "预热模式", - _ => $"未知({produceModel})" - }; - string runStatusDesc = runStatus switch { 1 => "空闲", 2 => "运行中", 3 => "故障", _ => $"未知({runStatus})" }; - string onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线"; - - // 计算整体工位合格标识(所有螺钉合格则工位合格) - var allScrewQualified = new[] { screw1Result, screw2Result, screw3Result, screw4Result, screw5Result, screw6Result, screw7Result } - .All(s => s == 1); - string qualificationFlag = allScrewQualified ? "1" : "0"; - - // 调试日志:输出关键读取结果 - Console.WriteLine($"OP080-1({ip})读取结果:产品名称={productName},运行状态={runStatusDesc},订单名称={orderName},螺钉整体合格={allScrewQualified}"); - - // 5. 构建数据实体(严格匹配PlcProductionData字段定义) - var plcData = new PlcProductionData - { - // 基础字段 - PlcIp = ip.Trim(), - OccurTime = DateTime.Now, - LineCode = "line2", // 可根据实际产线调整 - WorkstationCode = workstationCode, - ProductName = productName ?? string.Empty, - ProductCode = njPcbsn ?? string.Empty, // 拧紧位PCB SN作为产品编码 - - // 合格/返工标志 - QualificationFlag = qualificationFlag, - ReworkFlag = reworkFlag, - - // 设备状态相关 - Automanual = machineModel, // 设备模式:0-自动,1-手动 - Runstatus = runStatus, // 运行状态:1=空闲,2=运行中,3=故障 - OnlineStatus = onlineStatusDesc, // 设备在线状态1=离线,0=在线 - ProduceModel = produceModelDesc, // 生产模式描述 - - // 托盘号相关(拆分合装/拧紧位托盘号) - TrayNo = $"{hzTrayNo}!{njTrayNo}", // 合并显示 - AssemblyTrayNo = hzTrayNo.ToString(), // 合装位托盘号 - TightenTrayNo = njTrayNo.ToString(), // 拧紧位托盘号 - - // SN相关字段 - SN1 = hzMachineSN ?? string.Empty, // 合装位机壳SN - SN2 = njMachineSN ?? string.Empty, // 拧紧位机壳SN - AssemblyHousingSN = hzMachineSN ?? string.Empty, // 合装位机壳SN - AssemblyPCBSN = hzPcbsn ?? string.Empty, // 合装位PCB SN - TightenHousingSN = njMachineSN ?? string.Empty, // 拧紧位机壳SN - TightenPCBSN = njPcbsn ?? string.Empty, // 拧紧位PCB SN - - // 螺钉相关字段(严格匹配实体类) - Screw1Result = screw1Result.ToString(), - Screw1Torque = screw1Torque.ToString("0.00"), - Screw1Depth = screw1Depth.ToString("0.00"), - Screw1Angle = screw1Angle.ToString("0.00"), - Screw1TightenTime = screw1Time.ToString("0.00"), - - Screw2Result = screw2Result.ToString(), - Screw2Torque = screw2Torque.ToString("0.00"), - Screw2Depth = screw2Depth.ToString("0.00"), - Screw2Angle = screw2Angle.ToString("0.00"), - Screw2TightenTime = screw2Time.ToString("0.00"), - - Screw3Result = screw3Result.ToString(), - Screw3Torque = screw3Torque.ToString("0.00"), - Screw3Depth = screw3Depth.ToString("0.00"), - Screw3Angle = screw3Angle.ToString("0.00"), - Screw3TightenTime = screw3Time.ToString("0.00"), - - Screw4Result = screw4Result.ToString(), - Screw4Torque = screw4Torque.ToString("0.00"), - Screw4Depth = screw4Depth.ToString("0.00"), - Screw4Angle = screw4Angle.ToString("0.00"), - Screw4TightenTime = screw4Time.ToString("0.00"), - - Screw5Result = screw5Result.ToString(), - Screw5Torque = screw5Torque.ToString("0.00"), - Screw5Depth = screw5Depth.ToString("0.00"), - Screw5Angle = screw5Angle.ToString("0.00"), - Screw5TightenTime = screw5Time.ToString("0.00"), - - Screw6Result = screw6Result.ToString(), - Screw6Torque = screw6Torque.ToString("0.00"), - Screw6Depth = screw6Depth.ToString("0.00"), - Screw6Angle = screw6Angle.ToString("0.00"), - Screw6TightenTime = screw6Time.ToString("0.00"), - - Screw7Result = screw7Result.ToString(), - Screw7Torque = screw7Torque.ToString("0.00"), - Screw7Depth = screw7Depth.ToString("0.00"), - Screw7Angle = screw7Angle.ToString("0.00"), - Screw7TightenTime = screw7Time.ToString("0.00"), - - // 系统字段 - CreatedBy = "PLC", - CreatedTime = DateTime.Now, - // 可选字段(无值时置空) - ParamName = string.Empty, - ParamValue = string.Empty, - ProductionCycle = null, - Remark = string.Empty, - UpdatedBy = string.Empty, - UpdatedTime = null, - ProductModel = string.Empty, // 无产品型号数据时置空 - WorkstationName = string.Empty, // 无工站名称数据时置空 - CameraResult = string.Empty // 无相机结果数据时置空 - }; - return plcData; + // 增强异常日志:包含堆栈,便于定位问题 + Console.WriteLine($"OP080-1({ip})数据读取异常:{ex.Message}\n{ex.StackTrace}"); + // 异常时返回基础实体,避免业务空引用 + return new PlcProductionData + { + PlcIp = ip, + WorkstationCode = workstationCode, + CreatedBy = "PLC", + CreatedTime = DateTime.Now, + OnlineStatus = "读取异常" + }; + } } + /// /// 读取OP080-2 数据 /// @@ -1258,7 +1361,7 @@ namespace RIZO.Admin.WebApi.PLC.Service // 2. 解构字段 var (productModel, productName, sn1, sn2) = strFields; - var (runStatus, machineModel, onlineStatus,produceModel, + var (runStatus, machineModel, onlineStatus, produceModel, trayNo, productTotalResult, screw1Result, screw2Result, screw3Result, screw4Result, screw5Result, screw6Result, screw7Result) = intFields; @@ -1400,7 +1503,7 @@ namespace RIZO.Admin.WebApi.PLC.Service catch (Exception ex) { Console.WriteLine($"OP080-2({ip})数据读取异常:{ex.Message}"); - return null; + return null; } } #endregion @@ -2033,7 +2136,38 @@ namespace RIZO.Admin.WebApi.PLC.Service catch (Exception ex) { // 标准化日志格式,包含更多上下文信息 - Console.WriteLine($"[{DateTime.Now}] OP070-1({ip}) {plcName} 写保存请求返回值失败[目标值:{returnValue}]:{ex.Message}"); + Console.WriteLine($"[{DateTime.Now}]{plcName}({ip}) 写保存请求返回值失败[目标值:{returnValue}]:{ex.Message}"); + } + } + /// + /// 异步复位上传请求(独立方法,非阻塞) + /// + private async Task ResetUploadRequestAsync(Plc plc, string ip, string uploadRequestAddr) + { + try + { + // 若WritePlcValue无异步版本,用Task.Run包装避免阻塞 + await Task.Run(() => WritePlcValue(plc, uploadRequestAddr, "0")); + } + catch (Exception ex) + { + Console.WriteLine($"({ip})写上传请求复位失败:{ex.Message}"); + } + } + + /// + /// 异步复位保存请求(独立方法,非阻塞) + /// + private async Task ResetSaveRequestAsync(Plc plc, string ip, string saveRequestAddr) + { + try + { + // 若WritePlcValue无异步版本,用Task.Run包装避免阻塞 + await Task.Run(() => WritePlcValue(plc, saveRequestAddr, "0")); + } + catch (Exception ex) + { + Console.WriteLine($"({ip})写保存请求复位失败:{ex.Message}"); } } }