diff --git a/RIZO.Admin.WebApi/PLC/Service/PlcService.cs b/RIZO.Admin.WebApi/PLC/Service/PlcService.cs index 4a4d6d0..17e7ead 100644 --- a/RIZO.Admin.WebApi/PLC/Service/PlcService.cs +++ b/RIZO.Admin.WebApi/PLC/Service/PlcService.cs @@ -165,8 +165,92 @@ namespace RIZO.Admin.WebApi.PLC.Service { "7号螺钉_深度", "DB1016.DBD3278" }, // Real { "7号螺钉_角度", "DB1016.DBD3282" }, // Real { "7号螺钉_拧紧时间", "DB1016.DBD3286" }, // Real + }; + + // OP080-2 专属地址映射(PCBA拧紧工位,DB1001) + private readonly Dictionary _op080_2StringMap = new() + { + // { "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte + { "产品型号", ("DB1001.DBB1000", 48) }, // String[48] + { "产品名称", ("DB1001.DBB1054", 48) }, // String[48] + { "SN1", ("DB1001.DBB2100", 28) }, // String[28] - 条码查询 + { "SN2", ("DB1001.DBB2260", 28) }, // String[28] - 结果上传条码 }; + private readonly Dictionary _op080_2IntMap = new() + { + { "运行状态", "DB1001.DBW0" }, // Int - 1=空闲,2=运行中,3=故障 + { "设备模式", "DB1001.DBW2" }, // Int - 1=空模式;2=手动;4=初始化;8=自动;16=CycleStop + { "设备在线状态", "DB1001.DBW4" }, // Int - 1=离线,0=在线 + { "ByPass", "DB1001.DBW6" }, // Int - 1=ByPass,0=正常模式 + { "生产模式", "DB1001.DBW8" }, // Int - 1=点检,2=返工,4=样件,5=正常 + + //{ "实际产量", "DB1001.DBD1104" }, // DInt + //{ "合格数量", "DB1001.DBD1108" }, // DInt + //{ "失败数量", "DB1001.DBD1112" }, // DInt + + // 请求信号 + { "查询请求", "DB1001.DBW2000" }, // Int - 1=请求开始,0=无请求 + { "保存请求", "DB1001.DBW2002" }, // Int - 1=请求,0=无请求 + + // 托盘号 + { "托盘号", "DB1001.DBW2290" }, // Int + + // 产品总结果 + { "产品总结果", "DB1001.DBW2292" }, // Int + + // 1号螺钉 + { "1号螺钉_结果", "DB1001.DBW2294" }, // Int + { "1号螺钉_扭矩", "DB1001.DBD2296" }, // Real + { "1号螺钉_深度", "DB1001.DBD2300" }, // Real + { "1号螺钉_角度", "DB1001.DBD2304" }, // Real + { "1号螺钉_拧紧时间", "DB1001.DBD2308" }, // Real + + // 2号螺钉 + { "2号螺钉_结果", "DB1001.DBW2312" }, // Int + { "2号螺钉_扭矩", "DB1001.DBD2314" }, // Real + { "2号螺钉_深度", "DB1001.DBD2318" }, // Real + { "2号螺钉_角度", "DB1001.DBD2322" }, // Real + { "2号螺钉_拧紧时间", "DB1001.DBD2326" }, // Real + + // 3号螺钉 + { "3号螺钉_结果", "DB1001.DBW2330" }, // Int + { "3号螺钉_扭矩", "DB1001.DBD2332" }, // Real + { "3号螺钉_深度", "DB1001.DBD2336" }, // Real + { "3号螺钉_角度", "DB1001.DBD2340" }, // Real + { "3号螺钉_拧紧时间", "DB1001.DBD2344" }, // Real + + // 4号螺钉 + { "4号螺钉_结果", "DB1001.DBW2348" }, // Int + { "4号螺钉_扭矩", "DB1001.DBD2350" }, // Real + { "4号螺钉_深度", "DB1001.DBD2354" }, // Real + { "4号螺钉_角度", "DB1001.DBD2358" }, // Real + { "4号螺钉_拧紧时间", "DB1001.DBD2362" }, // Real + + // 5号螺钉 + { "5号螺钉_结果", "DB1001.DBW2366" }, // Int + { "5号螺钉_扭矩", "DB1001.DBD2368" }, // Real + { "5号螺钉_深度", "DB1001.DBD2372" }, // Real + { "5号螺钉_角度", "DB1001.DBD2376" }, // Real + { "5号螺钉_拧紧时间", "DB1001.DBD2380" }, // Real + + // 6号螺钉 + { "6号螺钉_结果", "DB1001.DBW2384" }, // Int + { "6号螺钉_扭矩", "DB1001.DBD2386" }, // Real + { "6号螺钉_深度", "DB1001.DBD2390" }, // Real + { "6号螺钉_角度", "DB1001.DBD2394" }, // Real + { "6号螺钉_拧紧时间", "DB1001.DBD2398" }, // Real + + // 7号螺钉 + { "7号螺钉_结果", "DB1001.DBW2402" }, // Int + { "7号螺钉_扭矩", "DB1001.DBD2404" }, // Real + { "7号螺钉_深度", "DB1001.DBD2408" }, // Real + { "7号螺钉_角度", "DB1001.DBD2412" }, // Real + { "7号螺钉_拧紧时间", "DB1001.DBD2416" }, // Real + + // 节拍时间 + //{ "节拍时间", "DB1001.DBD3004" }, // Real + }; #endregion /// /// 构造函数(依赖注入获取PLC配置) @@ -230,7 +314,6 @@ namespace RIZO.Admin.WebApi.PLC.Service { plc = CreatePlcClient(cpuType, ip, rack, slot); bool isConnected = false; - // for循环替代while,逻辑更直观 try { await OpenPlcConnectionAsync(plc); @@ -306,12 +389,14 @@ namespace RIZO.Admin.WebApi.PLC.Service { prodData = await ReadOP075DataAsync(plc, ip, plcName); } - else if (plcName == "OP080-1" || plcName == "OP080-2") + else if (plcName == "OP080-1") { - int iSaveRequest1 = await ReadPlcIntAsync(plc, _op080_1IntMap["合装结果保存请求"]); - int iSaveRequest2 = await ReadPlcIntAsync(plc, _op080_1IntMap["拧紧结果保存请求"]); prodData = await ReadOP080_1DataAsync(plc, ip, plcName, strSaveRequest); } + else if (plcName == "OP080-2") + { + prodData = await ReadOP080_2DataAsync(plc, ip, plcName); + } // 6. 统一空值兜底(避免空引用) if (prodData != null) @@ -405,14 +490,14 @@ namespace RIZO.Admin.WebApi.PLC.Service float cycleTime = realFields; // 3. 写入保存请求(异步+增强异常日志) - try - { - WritePlcValue(plc, _op070_1IntMap["保存请求"], "0"); - } - catch (Exception ex) - { - Console.WriteLine($"OP070-1({ip})写保存请求失败:{ex.Message}"); - } + //try + //{ + // WritePlcValue(plc, _op070_1IntMap["保存请求"], "0"); + //} + //catch (Exception ex) + //{ + // Console.WriteLine($"OP070-1({ip})写保存请求失败:{ex.Message}"); + //} // 4. 极简条件计算(增强类型安全) var reworkFlag = produceModel == 4 ? "1" : "0"; @@ -512,14 +597,14 @@ namespace RIZO.Admin.WebApi.PLC.Service float cycleTime = realFields; // 3. 写入保存请求(异步+增强异常日志) - try - { - WritePlcValue(plc, _op075IntMap["保存请求"], "0"); - } - catch (Exception ex) - { - Console.WriteLine($"OP075({ip})写保存请求失败:{ex.Message}"); - } + //try + //{ + // WritePlcValue(plc, _op075IntMap["保存请求"], "0"); + //} + //catch (Exception ex) + //{ + // Console.WriteLine($"OP075({ip})写保存请求失败:{ex.Message}"); + //} // 4. 极简条件计算(增强类型安全) var reworkFlag = produceModel == 4 ? "1" : "0"; @@ -684,21 +769,21 @@ namespace RIZO.Admin.WebApi.PLC.Service ) = realFields; // 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}"); - } + //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}"); + //} // 4. 极简条件计算(增强类型安全) var reworkFlag = produceModel == 4 ? "1" : "0"; @@ -816,6 +901,235 @@ namespace RIZO.Admin.WebApi.PLC.Service return plcData; } + /// + /// 读取OP080-2 数据 + /// + /// + /// + /// + /// + /// + private async Task ReadOP080_2DataAsync(Plc plc, string ip, string plcName) + { + try + { + // 1. 批量并行读取所有字段 + var (strFields, intFields, realFields) = await Task.Run(async () => ( + // 字符串字段(增强空值和异常处理) + ( + await ReadPlcStringAsync(plc, _op080_2StringMap["产品型号"].Addr, _op080_2StringMap["产品型号"].Len), + await ReadPlcStringAsync(plc, _op080_2StringMap["产品名称"].Addr, _op080_2StringMap["产品名称"].Len), + await ReadPlcStringAsync(plc, _op080_2StringMap["SN1"].Addr, _op080_2StringMap["SN1"].Len), + await ReadPlcStringAsync(plc, _op080_2StringMap["SN2"].Addr, _op080_2StringMap["SN2"].Len) + ), + // Int字段(使用增强版ReadPlcIntAsync) + ( + // 基础状态字段 + await ReadPlcIntAsync(plc, _op080_2IntMap["运行状态"]), + await ReadPlcIntAsync(plc, _op080_2IntMap["设备模式"]), + await ReadPlcIntAsync(plc, _op080_2IntMap["设备在线状态"]), + //await ReadPlcIntAsync(plc, _op080_2IntMap["ByPass"]), + await ReadPlcIntAsync(plc, _op080_2IntMap["生产模式"]), + // 托盘号+产品总结果 + await ReadPlcIntAsync(plc, _op080_2IntMap["托盘号"]), + await ReadPlcIntAsync(plc, _op080_2IntMap["产品总结果"]), + // 螺钉结果字段 + await ReadPlcIntAsync(plc, _op080_2IntMap["1号螺钉_结果"]), + await ReadPlcIntAsync(plc, _op080_2IntMap["2号螺钉_结果"]), + await ReadPlcIntAsync(plc, _op080_2IntMap["3号螺钉_结果"]), + await ReadPlcIntAsync(plc, _op080_2IntMap["4号螺钉_结果"]), + await ReadPlcIntAsync(plc, _op080_2IntMap["5号螺钉_结果"]), + await ReadPlcIntAsync(plc, _op080_2IntMap["6号螺钉_结果"]), + await ReadPlcIntAsync(plc, _op080_2IntMap["7号螺钉_结果"]) + ), + // Real字段(螺钉扭矩/深度/角度/时间) + ( + // 1号螺钉Real字段 + await ReadPlcRealAsync(plc, _op080_2IntMap["1号螺钉_扭矩"]), + await ReadPlcRealAsync(plc, _op080_2IntMap["1号螺钉_深度"]), + await ReadPlcRealAsync(plc, _op080_2IntMap["1号螺钉_角度"]), + await ReadPlcRealAsync(plc, _op080_2IntMap["1号螺钉_拧紧时间"]), + // 2号螺钉Real字段 + await ReadPlcRealAsync(plc, _op080_2IntMap["2号螺钉_扭矩"]), + await ReadPlcRealAsync(plc, _op080_2IntMap["2号螺钉_深度"]), + await ReadPlcRealAsync(plc, _op080_2IntMap["2号螺钉_角度"]), + await ReadPlcRealAsync(plc, _op080_2IntMap["2号螺钉_拧紧时间"]), + // 3号螺钉Real字段 + await ReadPlcRealAsync(plc, _op080_2IntMap["3号螺钉_扭矩"]), + await ReadPlcRealAsync(plc, _op080_2IntMap["3号螺钉_深度"]), + await ReadPlcRealAsync(plc, _op080_2IntMap["3号螺钉_角度"]), + await ReadPlcRealAsync(plc, _op080_2IntMap["3号螺钉_拧紧时间"]), + // 4号螺钉Real字段 + await ReadPlcRealAsync(plc, _op080_2IntMap["4号螺钉_扭矩"]), + await ReadPlcRealAsync(plc, _op080_2IntMap["4号螺钉_深度"]), + await ReadPlcRealAsync(plc, _op080_2IntMap["4号螺钉_角度"]), + await ReadPlcRealAsync(plc, _op080_2IntMap["4号螺钉_拧紧时间"]), + // 5号螺钉Real字段 + await ReadPlcRealAsync(plc, _op080_2IntMap["5号螺钉_扭矩"]), + await ReadPlcRealAsync(plc, _op080_2IntMap["5号螺钉_深度"]), + await ReadPlcRealAsync(plc, _op080_2IntMap["5号螺钉_角度"]), + await ReadPlcRealAsync(plc, _op080_2IntMap["5号螺钉_拧紧时间"]), + // 6号螺钉Real字段 + await ReadPlcRealAsync(plc, _op080_2IntMap["6号螺钉_扭矩"]), + await ReadPlcRealAsync(plc, _op080_2IntMap["6号螺钉_深度"]), + await ReadPlcRealAsync(plc, _op080_2IntMap["6号螺钉_角度"]), + await ReadPlcRealAsync(plc, _op080_2IntMap["6号螺钉_拧紧时间"]), + // 7号螺钉Real字段 + await ReadPlcRealAsync(plc, _op080_2IntMap["7号螺钉_扭矩"]), + await ReadPlcRealAsync(plc, _op080_2IntMap["7号螺钉_深度"]), + await ReadPlcRealAsync(plc, _op080_2IntMap["7号螺钉_角度"]), + await ReadPlcRealAsync(plc, _op080_2IntMap["7号螺钉_拧紧时间"]) + ) + )); + + // 2. 解构字段 + var (productModel, productName, sn1, sn2) = strFields; + + var (runStatus, machineModel, onlineStatus,produceModel, + trayNo, productTotalResult, + screw1Result, screw2Result, screw3Result, + screw4Result, screw5Result, screw6Result, screw7Result) = intFields; + + // 解构螺钉Real字段 + var ( + // 1号螺钉 + screw1Torque, screw1Depth, screw1Angle, screw1Time, + // 2号螺钉 + screw2Torque, screw2Depth, screw2Angle, screw2Time, + // 3号螺钉 + screw3Torque, screw3Depth, screw3Angle, screw3Time, + // 4号螺钉 + screw4Torque, screw4Depth, screw4Angle, screw4Time, + // 5号螺钉 + screw5Torque, screw5Depth, screw5Angle, screw5Time, + // 6号螺钉 + screw6Torque, screw6Depth, screw6Angle, screw6Time, + // 7号螺钉 + screw7Torque, screw7Depth, screw7Angle, screw7Time + ) = realFields; + + // 3. 写入保存请求复位 + //try + //{ + // WritePlcValue(plc, _op080_2IntMap["保存请求"], "0"); + //} + //catch (Exception ex) + //{ + // Console.WriteLine($"OP080-2({ip})写保存请求失败:{ex.Message}"); + //} + + // 4. 业务逻辑计算 + // 返工标志:生产模式=2时为返工 + var reworkFlag = produceModel == 2 ? "1" : "0"; + // 生产模式描述(OP080-2:1=点检,2=返工,4=样件,5=正常) + string produceModelDesc = produceModel switch + { + 1 => "点检模式", + 2 => "返工模式", + 4 => "样件模式", + 5 => "正常模式", + _ => $"未知({produceModel})" + }; + // 运行状态描述(1=空闲,2=运行中,3=故障) + string runStatusDesc = runStatus switch { 1 => "空闲", 2 => "运行中", 3 => "故障", _ => $"未知({runStatus})" }; + // 在线状态描述(1=离线,0=在线) + string onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线"; + // 合格标识:优先用产品总结果,无则判断所有螺钉结果 + string qualificationFlag = productTotalResult switch + { + 1 => "1", // 总结果OK + 2 => "0", // 总结果NG + _ => new[] { screw1Result, screw2Result, screw3Result, screw4Result, screw5Result, screw6Result, screw7Result } + .All(s => s == 1) ? "1" : "0" // 总结果未知时,判断所有螺钉是否合格 + }; + + // 调试日志:输出关键读取结果 + Console.WriteLine($"OP080-2({ip})读取结果:产品型号={productModel},运行状态={runStatusDesc},产品名称={productName},合格标识={qualificationFlag}"); + + // 5. 构建数据实体(严格匹配PlcProductionData,适配OP080-2字段) + var plcData = new PlcProductionData + { + // 基础字段 + PlcIp = ip.Trim(), + OccurTime = DateTime.Now, + LineCode = "line2", // 按实际产线调整 + WorkstationCode = plcName, // 直接使用传入的plcName作为工位编码 + ProductModel = productModel ?? string.Empty, // OP080-2有产品型号字段 + ProductName = productName ?? string.Empty, + ProductCode = sn2 ?? string.Empty, // 结果上传条码作为产品编码 + + // 合格/返工标志 + QualificationFlag = qualificationFlag, + ReworkFlag = reworkFlag, + + // 设备状态相关 + Automanual = machineModel, // 设备模式:1=空模式;2=手动;4=初始化;8=自动;16=CycleStop + Runstatus = runStatus, // 运行状态 + OnlineStatus = onlineStatusDesc, // 在线状态 + ProduceModel = produceModelDesc, // 生产模式描述 + + // 托盘号 + TrayNo = trayNo.ToString(), // OP080-2只有单个托盘号 + + // SN相关字段 + SN1 = sn1 ?? string.Empty, // 条码查询SN + SN2 = sn2 ?? string.Empty, // 结果上传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, + }; + return plcData; + } + catch (Exception ex) + { + Console.WriteLine($"OP080-2({ip})数据读取异常:{ex.Message}"); + return null; + } + } #endregion // 可选:添加连接池清理方法(防止长期运行导致连接泄露)