2026-01-31 10:00:18 +08:00

5801 lines
303 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 统一引入所有必要命名空间
using JinianNet.JNTemplate;
using MDM.Model.Process;
using MDM.Services.Plant;
using Microsoft.Extensions.Options;
using NPOI.SS.Formula.Functions;
using Quartz;
using RIZO.Admin.WebApi.PLC.Model;
using RIZO.Common;
using RIZO.Model.MES.product_trace;
using S7.Net;
using SqlSugar;
using SqlSugar.IOC;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace RIZO.Admin.WebApi.PLC.Service
{
/// <summary>
/// PLC通信服务封装连接、读写、生产数据采集等功能
/// </summary>
public class PlcService : IDisposable
{
#region
// 标记是否已释放资源,避免重复释放
private bool _disposed = false;
// PLC配置参数从配置文件注入
private readonly List<PlcConfig> _plcConfigs;
private readonly GlobalPlcConfig _globalConfig;
private PlcProductionDataService _plcProductionDataService = new PlcProductionDataService();
private PlantWorkstationService _plantWorkstationService = new PlantWorkstationService();
private PlcOperationResultService _plcOperationResultService = new PlcOperationResultService();
// 先在类中添加2个核心优化字段支撑高频访问
private readonly SemaphoreSlim _concurrencySemaphore = new SemaphoreSlim(15, 50); // 限制20并发适配50台PLC
private readonly ConcurrentDictionary<string, (Plc Client, DateTime LastUsedTime)> _plcConnPool = new(); // 连接池
#region PLC地址块儿映射
//MES返回PLC请求映射
private readonly Dictionary<string, string> _mesIntReturnMap = new()
{
{ "设备使能", "DB1000.DBW0" }, // Int
{ "工位开始查询结果", "DB1000.DBW2000" }, // Int
{ "保存结果", "DB1000.DBW2002" }, // Int
};
private readonly Dictionary<string, (string Addr, int Len)> _mesStringReturnMap = new()
{
{ "产品型号", ("DB1000.DBB1016", 14) }, // String[14]
{ "订单下发", ("DB1000.DBB1032", 50) }, // String[50]
};
private readonly Dictionary<string, string> _mesop058IntReturnMap = new()
{
{ "设备使能", "DB300.DBW0" }, // Int
{ "工位开始查询结果", "DB300.DBW2000" }, // Int
{ "保存结果", "DB300.DBW2002" }, // Int
};
private readonly Dictionary<string, (string Addr, int Len)> _mesop058StringReturnMap = new()
{
{ "产品型号", ("DB300.DBB1016", 14) }, // String[14]
{ "订单下发", ("DB300.DBB1032", 50) }, // String[50]
};
// OP020-2 专属地址映射合盖工位DB1001
private readonly Dictionary<string, (string Addr, int Len)> _op020_2StringMap = new()
{
{ "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte
{ "产品型号", ("DB1001.DBB1000", 48) }, // String[48]
{ "产品名称", ("DB1001.DBB1054", 48) }, // String[48]
{ "SN", ("DB1001.DBB2106", 48) } // String[48]
};
private readonly Dictionary<string, string> _op020_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=返工模式;8=换型模式;16=预热模式
//{ "实际产量", "DB1001.DBD1104" }, // DInt
//{ "合格数量", "DB1001.DBD1108" }, // DInt
//{ "失败数量", "DB1001.DBD1112" }, // DInt
{ "上传请求", "DB1001.DBW2002" }, // Int - 1=请求开始0=无请求
{ "托盘号", "DB1001.DBW2054" }, // Int
{ "总结果", "DB1001.DBW2158" }, // Int - 一个托盘上传四次结果
{ "节拍时间", "DB1001.DBD2988" } // Real
};
// OP020-3 专属地址映射热铆工位DB1001
private readonly Dictionary<string, (string Addr, int Len)> _op020_3StringMap = new()
{
{ "报警信息", ("DB1001.DBB88", 48) }, // Array[1..48] of Byte
{ "产品型号", ("DB1001.DBB4060", 48) }, // String[48]
{ "产品1SN", ("DB1001.DBB2300", 48) }, // String[48]
{ "产品2SN", ("DB1001.DBB2350", 48) }, // String[48]
{ "产品3SN", ("DB1001.DBB2400", 48) }, // String[48]
{ "产品4SN", ("DB1001.DBB2450", 48) } // String[48]
};
private readonly Dictionary<string, string> _op020_3IntMap = 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=返工模式;8=换型模式;16=预热模式
// 上传请求
{ "查询请求", "DB1001.DBW2000" }, // Int - 1:请求开始0:无请求
{ "上传请求", "DB1001.DBW2002" }, // Int - 1:请求开始0:无请求
// 节拍时间
{ "节拍时间", "DB1001.DBD2988" }, // Real
// 产品结果与产量
{ "合格数量", "DB1001.DBD4110" }, // DInt
{ "失败数量", "DB1001.DBD4114" }, // DInt
{ "实际数量", "DB1001.DBD4118" } // DInt
};
// OP020-4 专属地址映射pin压合&视觉检查工位DB1001
private readonly Dictionary<string, (string Addr, int Len)> _op020_4StringMap = new()
{
{ "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte
{ "产品型号", ("DB1001.DBB1000", 48) }, // String[48]
{ "产品名称", ("DB1001.DBB1054", 48) }, // String[48]
{ "产品1SN", ("DB1001.DBB2230", 40) }, // String[40]
{ "产品2SN", ("DB1001.DBB2360", 40) }, // String[40]
{ "产品3SN", ("DB1001.DBB2490", 40) }, // String[40]
{ "产品4SN", ("DB1001.DBB2620", 40) } // String[40]
};
private readonly Dictionary<string, string> _op020_4IntMap = 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=返工模式;8=换型模式;16=预热模式
// 上传请求
{ "产品1上传请求", "DB1001.DBW2002" }, // Int
{ "产品2上传请求", "DB1001.DBW2004" }, // Int
{ "产品3上传请求", "DB1001.DBW2006" }, // Int
{ "产品4上传请求", "DB1001.DBW2008" }, // Int
// 托盘号
{ "托盘号", "DB1001.DBW2070" }, // Int
// 产品结果
{ "产品1结果", "DB1001.DBW2274" }, // Int - 1:OK 2:NG
{ "产品2结果", "DB1001.DBW2404" }, // Int - 1:OK 2:NG
{ "产品3结果", "DB1001.DBW2534" }, // Int - 1:OK 2:NG
{ "产品4结果", "DB1001.DBW2664" }, // Int - 1:OK 2:NG
};
// OP050 专属地址映射点白胶DC744工位DB300
private readonly Dictionary<string, (string Addr, int Len)> _op050StringMap = new()
{
{ "报警信息", ("DB300.DBB680", 48) }, // Array[1..48] of Byte
{ "产品型号", ("DB300.DBB728", 48) }, // String[48]
{ "产品名称", ("DB300.DBB778", 48) }, // String[48]
{ "产品1SN", ("DB300.DBB50", 40) }, // String[40]
{ "产品2SN", ("DB300.DBB206", 40) }, // String[40]
{ "产品3SN", ("DB300.DBB362", 40) }, // String[40]
{ "产品4SN", ("DB300.DBB518", 40) } // String[40]
};
private readonly Dictionary<string, string> _op050IntMap = new()
{
// 基础状态
{ "运行状态", "DB300.DBW670" }, // Int - 1=空闲2=运行中3=故障
{ "设备模式", "DB300.DBW672" }, // Int - 1=空模式2=手动4=初始化8=自动16=CycleStop
{ "设备在线状态", "DB300.DBW674" }, // Int - 1=离线,0=在线
{ "ByPass", "DB300.DBW676" }, // Int - 1=ByPass,0=正常模式
{ "生产模式", "DB300.DBW678" }, // Int - 1=正常模式;2=清线模式;4=返工模式;8=换型模式;16=预热模式
// 上传与查询请求
{ "上传请求", "DB300.DBW42" }, // Int
{ "查询请求", "DB300.DBW44" }, // Int - 非0是查询%X1满足条码1查询……%X2满足条码2查询
// 产量数据
{ "实际产量", "DB300.DBD828" }, // DInt
{ "合格数量", "DB300.DBD832" }, // DInt
{ "失败数量", "DB300.DBD836" }, // DInt
// 节拍时间
{ "节拍时间", "DB300.DBD840" }, // Real
// 托盘号
{ "托盘号", "DB300.DBW844" }, // Int
};
// OP050-1 专属地址映射自动下料工位DB1001
private readonly Dictionary<string, (string Addr, int Len)> _op050_1StringMap = new()
{
{ "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte
{ "产品型号", ("DB1001.DBB1000", 48) }, // String[48]
{ "产品名称", ("DB1001.DBB1054", 48) } // String[48]
};
private readonly Dictionary<string, string> _op050_1IntMap = 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=返工模式;8=换型模式;16=预热模式
// 产量数据
{ "实际产量", "DB1001.DBD1104" }, // DInt
{ "合格数量", "DB1001.DBD1108" }, // DInt
{ "失败数量", "DB1001.DBD1112" }, // DInt
// 节拍时间
{ "节拍时间", "DB1001.DBD5086" }, // Real
};
// OP051扫码 专属地址映射Coating扫码工位假设使用 DB1002//待PLC给出
private readonly Dictionary<string, (string Addr, int Len)> _op051ScanStringMap = new()
{
{ "产品型号", ("DB1002.DBB1000", 48) }, // String[48]
{ "产品名称", ("DB1002.DBB1054", 48) }, // String[48]
{ "SN_1", ("DB1002.DBB50", 40) }, // String[40]
{ "SN_2", ("DB1002.DBB206", 40) }, // String[40]
{ "SN_3", ("DB1002.DBB362", 40) } // String[40]
};
private readonly Dictionary<string, string> _op051ScanIntMap = new()
{
// 基础状态
{ "运行状态", "DB1002.DBW0" }, // Int - 1=空闲2=运行中3=故障
{ "设备模式", "DB1002.DBW2" }, // Int - 1=空模式2=手动4=初始化8=自动16=CycleStop
{ "设备在线状态", "DB1002.DBW4" }, // Int - 1=离线,0=在线
{ "生产模式", "DB1002.DBW8" }, // Int - 1=正常模式;2=清线模式;4=返工模式;8=换型模式;16=预热模式
// 操作请求
{ "查询请求", "DB1002.DBW44" }, // Int - 非0为查询
{ "上传结果请求", "DB1002.DBW46" }, // Int - 非0为上传
// 托盘号
{ "托盘号", "DB1002.DBW844" } // Int
};
// OP057 专属地址映射(压装定位销&激光打标工位DB1001
private readonly Dictionary<string, (string Addr, int Len)> _op057StringMap = new()
{
{ "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte
{ "产品型号", ("DB1001.DBB1000", 48) }, // String[48]
{ "产品名称", ("DB1001.DBB1054", 48) }, // String[48]
{ "SN_1", ("DB1001.DBB2100", 40) }, // String[40]
{ "SN_2", ("DB1001.DBB2904", 40) } // String[40]
};
private readonly Dictionary<string, string> _op057IntMap = 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=无请求
{ "1#产品结果保存请求", "DB1001.DBW2002" }, // Int - 1=请求0=无请求
// 产品结果
{ "产品总结果", "DB1001.DBW2948" }, // Int - 1=OK2=NG
{ "1#销结果", "DB1001.DBW2950" }, // Int - 1=OK
{ "2#销结果", "DB1001.DBW2964" }, // Int - 1=OK
// 工艺参数Real
{ "1#销压力", "DB1001.DBD2952" }, // Real
{ "1#销行程", "DB1001.DBD2956" }, // Real
{ "2#销压力", "DB1001.DBD2966" }, // Real
{ "2#销行程", "DB1001.DBD2970" }, // Real
{ "节拍时间", "DB1001.DBD4662" }, // Real
};
// OP058 专属地址映射(压装定位销&激光打标工位DB1004
private readonly Dictionary<string, (string Addr, int Len)> _op058StringMap = new()
{
{ "产品型号", ("DB1004.DBB1000", 48) }, // String[48]
{ "产品名称", ("DB1004.DBB1054", 48) }, // String[48]
{ "SN_1", ("DB1004.DBB2234", 40) } // String[40] - 条码(查询、上传)
};
private readonly Dictionary<string, string> _op058IntMap = new()
{
// 产量数据
{ "实际产量", "DB1004.DBD1104" }, // DInt
{ "合格数量", "DB1004.DBD1108" }, // DInt
{ "失败数量", "DB1004.DBD1112" }, // DInt
// 产品结果
{ "产品总结果", "DB1004.DBW2278" }, // Int - 1=OK2=NG
{ "结果", "DB1004.DBW2280" }, // Int - 1=OK
// 工艺参数Real
{ "压力", "DB1004.DBD2282" }, // Real
{ "行程", "DB1004.DBD2286" }, // Real
{ "节拍时间", "DB1004.DBD2310" }, // Real
};
// OP060 专属地址映射高低压接头拧紧工位DB1001
private readonly Dictionary<string, (string Addr, int Len)> _op060StringMap = new()
{
{ "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte
{ "产品型号", ("DB1001.DBB1000", 48) }, // String[48]
{ "产品名称", ("DB1001.DBB1054", 48) }, // String[48]
{ "SN_1", ("DB1001.DBB2100", 40) }, // String[40] - 条码查询
{ "SN_2", ("DB1001.DBB2274", 40) } // String[40] - 结果上传条码
};
private readonly Dictionary<string, string> _op060IntMap = 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=无请求
{ "1#产品结果保存请求", "DB1001.DBW2002" }, // Int - 1=请求0=无请求
// 产品结果
{ "产品总结果", "DB1001.DBW2318" }, // Int - 1=OK2=NG
{ "1#螺丝结果", "DB1001.DBW2320" }, // Int
{ "2#螺丝结果", "DB1001.DBW2338" }, // Int
{ "3#螺丝结果", "DB1001.DBW2356" }, // Int
{ "4#螺丝结果", "DB1001.DBW2374" }, // Int
// 工艺参数Real
{ "1#螺丝扭矩", "DB1001.DBD2322" }, // Real
{ "1#螺丝深度", "DB1001.DBD2326" }, // Real
{ "1#螺丝角度", "DB1001.DBD2330" }, // Real
{ "1#螺丝时间", "DB1001.DBD2334" }, // Real
{ "2#螺丝扭矩", "DB1001.DBD2340" }, // Real
{ "2#螺丝深度", "DB1001.DBD2344" }, // Real
{ "2#螺丝角度", "DB1001.DBD2348" }, // Real
{ "2#螺丝时间", "DB1001.DBD2352" }, // Real
{ "3#螺丝扭矩", "DB1001.DBD2358" }, // Real
{ "3#螺丝深度", "DB1001.DBD2362" }, // Real
{ "3#螺丝角度", "DB1001.DBD2366" }, // Real
{ "3#螺丝时间", "DB1001.DBD2370" }, // Real
{ "4#螺丝扭矩", "DB1001.DBD2376" }, // Real
{ "4#螺丝深度", "DB1001.DBD2380" }, // Real
{ "4#螺丝角度", "DB1001.DBD2384" }, // Real
{ "4#螺丝时间", "DB1001.DBD2388" }, // Real
{ "节拍时间", "DB1001.DBD3030" }, // Real
};
// OP070-1 专属地址映射 点散热胶GF1500工位 OP070-2 点散热胶TC4060 OP070-3 点散热胶GF3500
private readonly Dictionary<string, (string Addr, int Len)> _op070_1StringMap = new()
{
//{ "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte
{ "订单名称", ("DB1001.DBB1000", 48) }, // String[48]
{ "产品名称", ("DB1001.DBB1054", 48) }, // String[48]
{ "产品型号", ("DB1001.DBB2006", 28) }, // String[28]
{ "SN_1", ("DB1001.DBB2100", 28) }, // String[28]
{ "SN_2", ("DB1001.DBB2134", 28) } // String[28]
};
private readonly Dictionary<string, string> _op070_1IntMap = new()
{
{ "运行状态", "DB1001.DBW0" }, // Int
{ "设备模式", "DB1001.DBW2" }, // Int
{ "设备在线状态", "DB1001.DBW4" }, // Int
{ "ByPass", "DB1001.DBW6" }, // Int
{ "生产模式", "DB1001.DBW8" }, // Int
{ "实际产量", "DB1001.DBD1104" }, // DInt
//{ "合格数量", "DB1001.DBD1108" }, // DInt
//{ "失败数量", "DB1001.DBD1112" }, // DInt
{ "查询请求", "DB1001.DBW2000" }, // Int
{ "保存请求", "DB1001.DBW2002" }, // Int
{ "托盘号", "DB1001.DBW2004" }, // Int
{ "相机结果", "DB1001.DBW2164" }, // Int
{ "站位结果", "DB1001.DBW2166" }, // Int
{ "节拍时间", "DB1001.DBD2168" }, // Real
};
// OP075 专属地址映射 PWM折弯&装配
private readonly Dictionary<string, (string Addr, int Len)> _op075StringMap = new()
{
//{ "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte
{ "订单名称", ("DB1001.DBB1000", 48) }, // String[48]
{ "产品名称", ("DB1001.DBB1054", 48) }, // String[48]
{ "产品型号", ("DB1001.DBB2006", 28) }, // String[28]
{ "SN_1", ("DB1001.DBB2100", 28) }, // String[28]
{ "SN_2", ("DB1001.DBB2192", 28) }, // String[28]
{ "芯片SN", ("DB1001.DBB2222", 28) } // String[28]
};
private readonly Dictionary<string, string> _op075IntMap = new()
{
{ "运行状态", "DB1001.DBW0" }, // Int
{ "设备模式", "DB1001.DBW2" }, // Int
{ "设备在线状态", "DB1001.DBW4" }, // Int
{ "ByPass", "DB1001.DBW6" }, // Int
{ "生产模式", "DB1001.DBW8" }, // Int
{ "实际产量", "DB1001.DBD1104" }, // DInt
//{ "合格数量", "DB1001.DBD1108" }, // DInt
//{ "失败数量", "DB1001.DBD1112" }, // DInt
{ "查询请求", "DB1001.DBW2000" }, // Int
{ "保存请求", "DB1001.DBW2002" }, // Int
{ "托盘号", "DB1001.DBW2004" }, // Int
{ "站位结果", "DB1001.DBW2252" }, // Int
{ "节拍时间", "DB1001.DBD2284" } // Real
};
// OP080-1 专属地址映射 PCBA组装&拧紧
private readonly Dictionary<string, (string Addr, int Len)> _op080_1StringMap = new()
{
//{ "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte
{ "订单名称", ("DB1001.DBB1000", 48) }, // String[48]
{ "产品名称", ("DB1001.DBB1054", 48) }, // String[48]
{ "合装位机壳_SN", ("DB1001.DBB2100", 28) }, // String[28]
{ "合装位PCB_SN", ("DB1001.DBB2130", 28) }, // String[28]
{ "拧紧位机壳_SN", ("DB1001.DBB2904", 28) }, // String[28]
{ "拧紧位PCB_SN", ("DB1001.DBB3092", 28) }, // String[28]
};
private readonly Dictionary<string, string> _op080_1IntMap = new()
{
{ "运行状态", "DB1001.DBW0" }, // Int
{ "设备模式", "DB1001.DBW2" }, // Int
{ "设备在线状态", "DB1001.DBW4" }, // Int
{ "ByPass", "DB1001.DBW6" }, // Int
{ "生产模式", "DB1001.DBW8" }, // Int
{ "实际产量", "DB1001.DBD1104" }, // DInt
{ "合格数量", "DB1001.DBD1108" }, // DInt
{ "失败数量", "DB1001.DBD1112" }, // DInt
{ "合装工位查询请求", "DB1001.DBW2000" }, // Int
{ "合装结果保存请求", "DB1001.DBW2004" }, // Int
{ "拧紧结果保存请求", "DB1001.DBW2006" }, // Int
{ "合装位托盘号", "DB1001.DBW2100" }, // Int
{ "拧紧位托盘号", "DB1001.DBW3152" }, // Int
// 2号螺钉
{ "2号螺钉_结果", "DB1001.DBW3164" }, // Int
{ "2号螺钉_扭矩", "DB1001.DBD3166" }, // Real
{ "2号螺钉_深度", "DB1001.DBD3170" }, // Real
{ "2号螺钉_角度", "DB1001.DBD3174" }, // Real
{ "2号螺钉_拧紧时间", "DB1001.DBD3178" }, // Real
// 3号螺钉
{ "3号螺钉_结果", "DB1001.DBW3182" }, // Int
{ "3号螺钉_扭矩", "DB1001.DBD3184" }, // Real
{ "3号螺钉_深度", "DB1001.DBD3188" }, // Real
{ "3号螺钉_角度", "DB1001.DBD3192" }, // Real
{ "3号螺钉_拧紧时间", "DB1001.DBD3196" }, // Real
// 4号螺钉
{ "4号螺钉_结果", "DB1001.DBW3200" }, // Int
{ "4号螺钉_扭矩", "DB1001.DBD3202" }, // Real
{ "4号螺钉_深度", "DB1001.DBD3206" }, // Real
{ "4号螺钉_角度", "DB1001.DBD3210" }, // Real
{ "4号螺钉_拧紧时间", "DB1001.DBD3214" }, // Real
// 1号螺钉
{ "1号螺钉_结果", "DB1001.DBW3218" }, // Int
{ "1号螺钉_扭矩", "DB1001.DBD3220" }, // Real
{ "1号螺钉_深度", "DB1001.DBD3224" }, // Real
{ "1号螺钉_角度", "DB1001.DBD3228" }, // Real
{ "1号螺钉_拧紧时间", "DB1001.DBD3232" }, // Real
// 5号螺钉
{ "5号螺钉_结果", "DB1001.DBW3236" }, // Int
{ "5号螺钉_扭矩", "DB1001.DBD3238" }, // Real
{ "5号螺钉_深度", "DB1001.DBD3242" }, // Real
{ "5号螺钉_角度", "DB1001.DBD3246" }, // Real
{ "5号螺钉_拧紧时间", "DB1001.DBD3250" }, // Real
// 6号螺钉
{ "6号螺钉_结果", "DB1001.DBW3254" }, // Int
{ "6号螺钉_扭矩", "DB1001.DBD3256" }, // Real
{ "6号螺钉_深度", "DB1001.DBD3260" }, // Real
{ "6号螺钉_角度", "DB1001.DBD3264" }, // Real
{ "6号螺钉_拧紧时间", "DB1001.DBD3268" }, // Real
// 7号螺钉
{ "7号螺钉_结果", "DB1001.DBW3272" }, // Int
{ "7号螺钉_扭矩", "DB1001.DBD3274" }, // Real
{ "7号螺钉_深度", "DB1001.DBD3278" }, // Real
{ "7号螺钉_角度", "DB1001.DBD3282" }, // Real
{ "7号螺钉_拧紧时间", "DB1001.DBD3286" }, // Real
};
// OP080-2 专属地址映射PCBA拧紧工位DB1001
private readonly Dictionary<string, (string Addr, int Len)> _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<string, string> _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
};
// OP080-3 专属地址映射PWM压装&CUP上料&拧紧工位DB1001
private readonly Dictionary<string, (string Addr, int Len)> _op080_3StringMap = new()
{
{ "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte
{ "产品型号", ("DB1001.DBB1000", 48) }, // String[48]
{ "产品名称", ("DB1001.DBB1054", 48) }, // String[48]
{ "SN_1", ("DB1001.DBB2100", 40) }, // String[40] - 条码查询
{ "SN_2", ("DB1001.DBB2200", 40) } // String[40] - 结果上传条码
};
private readonly Dictionary<string, string> _op080_3IntMap = 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.DBW2244" }, // Int
{ "压机结果", "DB1001.DBW2246" }, // Int
{ "左螺丝枪结果", "DB1001.DBW2264" }, // Int
{ "右螺丝枪结果", "DB1001.DBW2282" }, // Int
// 工艺参数Real
{ "压机左压力值", "DB1001.DBD2248" }, // Real
{ "压机右压力值", "DB1001.DBD2252" }, // Real
{ "压机行程值", "DB1001.DBD2256" }, // Real
{ "保压时间", "DB1001.DBD2260" }, // Real
{ "左螺丝枪扭矩", "DB1001.DBD2266" }, // Real
{ "左螺丝枪角度", "DB1001.DBD2270" }, // Real
{ "左螺丝枪深度", "DB1001.DBD2274" }, // Real
{ "左螺丝枪时间", "DB1001.DBD2278" }, // Real
{ "右螺丝枪扭矩", "DB1001.DBD2284" }, // Real
{ "右螺丝枪角度", "DB1001.DBD2288" }, // Real
{ "右螺丝枪深度", "DB1001.DBD2292" }, // Real
{ "右螺丝枪时间", "DB1001.DBD2296" }, // Real
{ "节拍时间", "DB1001.DBD2450" }, // Real
// 托盘号
{ "托盘号", "DB1001.DBW2142" } // Int
};
// OP085 专属地址映射自动上料到波峰焊工位DB1001
private readonly Dictionary<string, (string Addr, int Len)> _op085StringMap = new()
{
{ "报警信息", ("DB1030.DBB58", 48) }, // Array[1..48] of Byte
{ "产品型号", ("DB1030.DBB1000", 48) }, // String[48]
{ "产品名称", ("DB1030.DBB1054", 48) }, // String[48]
{ "波峰焊托盘条码", ("DB1030.DBB2070", 40) }, // String[40]
{ "穴位1产品SN", ("DB1030.DBB2486", 40) }, // String[40]
{ "穴位2产品SN", ("DB1030.DBB2528", 40) }, // String[40]
{ "穴位3产品SN", ("DB1030.DBB2570", 40) }, // String[40]
{ "穴位4产品SN", ("DB1030.DBB2612", 40) } // String[40]
};
private readonly Dictionary<string, string> _op085IntMap = 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.DBW2002" }, // Int - 1=请求开始0=无请求
{ "线体托盘号", "DB1001.DBW2070" }, // Int
// 工艺参数
{ "节拍时间", "DB1001.DBD2242" } // Real
};
// OP100 专属地址映射(手动上料壳体&盖板工位DB1001
private readonly Dictionary<string, (string Addr, int Len)> _op100StringMap = new()
{
{ "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte
{ "产品型号", ("DB1001.DBB1000", 48) }, // String[48]
{ "产品名称", ("DB1001.DBB1054", 48) }, // String[48]
{ "产品SN", ("DB1001.DBB2100", 28) } // String[28]
};
private readonly Dictionary<string, string> _op100IntMap = 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.DBW2070" }, // Int
// 工艺参数
{ "节拍时间", "DB1001.DBD2958" } // Real
};
// OP1011 专属地址映射HV连接器装配工位DB1001
private readonly Dictionary<string, (string Addr, int Len)> _op1011StringMap = new()
{
{ "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte
{ "产品型号", ("DB1001.DBB1000", 48) }, // String[48]
{ "产品名称", ("DB1001.DBB1054", 48) }, // String[48]
{ "查询SN", ("DB1001.DBB2100", 40) }, // String[40]
{ "上传结果SN", ("DB1001.DBB2364", 40) } // String[40]
};
private readonly Dictionary<string, string> _op1011IntMap = 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.DBW998" }, // Int - 给MES提供螺钉枪程序号控制切换
// 产量数据
{ "实际产量", "DB1001.DBD1104" }, // DInt
{ "合格数量", "DB1001.DBD1108" }, // DInt
{ "失败数量", "DB1001.DBD1112" }, // DInt
// 操作请求
{ "开始查询请求", "DB1001.DBW2000" }, // Int - 1=请求开始0=无请求
{ "结果保存请求", "DB1001.DBW2002" }, // Int - 1=请求开始0=无请求
{ "请求设备MES传送螺丝", "DB1001.DBW2004" }, // Int
// 产品结果
{ "产品总结果", "DB1001.DBW2364" }, // Int
{ "1#结果", "DB1001.DBW2464" }, // Int - 0=无结果1=OK2=NG
{ "2#结果", "DB1001.DBW2466" }, // Int - 0=无结果1=OK2=NG
{ "3#结果", "DB1001.DBW2468" }, // Int - 0=无结果1=OK2=NG
{ "4#结果", "DB1001.DBW2470" }, // Int - 0=无结果1=OK2=NG
// 工艺参数Real
{ "1#扭矩", "DB1001.DBD2384" }, // Real
{ "2#扭矩", "DB1001.DBD2388" }, // Real
{ "3#扭矩", "DB1001.DBD2392" }, // Real
{ "4#扭矩", "DB1001.DBD2396" }, // Real
{ "1#转角", "DB1001.DBD2424" }, // Real
{ "2#转角", "DB1001.DBD2428" }, // Real
{ "3#转角", "DB1001.DBD2432" }, // Real
{ "4#转角", "DB1001.DBD2436" }, // Real
{ "1#深度", "DB1001.DBD2484" }, // Real
{ "2#深度", "DB1001.DBD2488" }, // Real
{ "3#深度", "DB1001.DBD2492" }, // Real
{ "4#深度", "DB1001.DBD2496" }, // Real
{ "节拍时间", "DB1001.DBD2690" } // Real
};
// OP1012 专属地址映射Ring terminal装配工位DB1001
private readonly Dictionary<string, (string Addr, int Len)> _op1012StringMap = new()
{
{ "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte
{ "产品型号", ("DB1001.DBB1000", 48) }, // String[48]
{ "产品名称", ("DB1001.DBB1054", 48) }, // String[48]
{ "查询SN", ("DB1001.DBB2100", 40) }, // String[40]
{ "上传SN", ("DB1001.DBB2320", 40) } // String[40]
};
private readonly Dictionary<string, string> _op1012IntMap = 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.DBW998" }, // Int
// 产量数据
{ "实际产量", "DB1001.DBD1104" }, // DInt
{ "合格数量", "DB1001.DBD1108" }, // DInt
{ "失败数量", "DB1001.DBD1112" }, // DInt
// 操作请求
{ "查询请求", "DB1001.DBW2000" }, // Int - 1=请求开始0=无请求
{ "结果保存请求", "DB1001.DBW2002" }, // Int - 1=请求开始0=无请求
{ "请求传送打螺丝结果", "DB1001.DBW2001" }, // Int
// 产品结果
{ "产品总结果", "DB1001.DBW2364" }, // Int - 1=OK2=NG
{ "1#结果", "DB1001.DBW2464" }, // Int - 1=OK2=NG
{ "2#结果", "DB1001.DBW2466" }, // Int - 1=OK2=NG
// 工艺参数Real
{ "1#扭矩", "DB1001.DBD2384" }, // Real
{ "2#扭矩", "DB1001.DBD2388" }, // Real
{ "1#转角", "DB1001.DBD2424" }, // Real
{ "2#转角", "DB1001.DBD2428" }, // Real
{ "1#深度", "DB1001.DBD2484" }, // Real
{ "2#深度", "DB1001.DBD2488" }, // Real
{ "节拍时间", "DB1001.DBD2690" } // Real
};
// OP102 专属地址映射等离子处理工位DB1001
private readonly Dictionary<string, (string Addr, int Len)> _op102StringMap = new()
{
{ "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte
{ "产品型号", ("DB1001.DBB1000", 48) }, // String[48]
{ "产品名称", ("DB1001.DBB1054", 48) }, // String[48]
{ "查询SN", ("DB1001.DBB2100", 28) }, // String[28]
{ "上传结果SN", ("DB1001.DBB2134", 28) } // String[28]
};
private readonly Dictionary<string, string> _op102IntMap = 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.DBW2104" }, // Int
{ "站位结果", "DB1001.DBW2166" }, // Int
// 工艺参数
{ "节拍时间", "DB1001.DBD2168" } // Real
};
// OP110-1 专属地址映射点胶封胶Q3-3636工位DB1001
private readonly Dictionary<string, (string Addr, int Len)> _op110_1StringMap = new()
{
{ "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte
{ "产品型号", ("DB1001.DBB1000", 48) }, // String[48]
{ "产品名称", ("DB1001.DBB1054", 48) }, // String[48]
{ "查询SN", ("DB1001.DBB2100", 28) }, // String[28]
{ "上传结果SN", ("DB1001.DBB2134", 28) } // String[28]
};
private readonly Dictionary<string, string> _op110_1IntMap = 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.DBW2004" }, // Int
{ "相机结果", "DB1001.DBW2164" }, // Int
{ "站位结果", "DB1001.DBW2166" }, // Int
// 工艺参数
{ "节拍时间", "DB1001.DBD2168" } // Real
};
// OP110-2 专属地址映射(盖板组装&拧紧工位DB1001
private readonly Dictionary<string, (string Addr, int Len)> _op110_2StringMap = new()
{
{ "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte
{ "产品型号", ("DB1001.DBB1000", 48) }, // String[48]
{ "产品名称", ("DB1001.DBB1054", 48) }, // String[48]
{ "合装工位查询SN", ("DB1001.DBB2100", 28) }, // String[28]
{ "拧紧工位上传结果SN", ("DB1001.DBB2616", 28) } // String[28]
};
private readonly Dictionary<string, string> _op110_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.DBW2006" }, // Int - 1=请求开始0=无请求
// 合装与托盘
{ "合装工位托盘号", "DB1001.DBW2130" }, // Int
{ "托盘号", "DB1001.DBW2646" }, // Int
{ "产品总结果", "DB1001.DBW2648" }, // Int
// 螺丝结果3#-7#
{ "3#螺丝结果", "DB1001.DBW2662" }, // Int
{ "5#螺丝结果", "DB1001.DBW2680" }, // Int
{ "6#螺丝结果", "DB1001.DBW2698" }, // Int
{ "1#螺丝结果", "DB1001.DBW2716" }, // Int
{ "2#螺丝结果", "DB1001.DBW2734" }, // Int
{ "4#螺丝结果", "DB1001.DBW2752" }, // Int
{ "7#螺丝结果", "DB1001.DBW2770" }, // Int
// 螺丝工艺参数Real
{ "3#扭矩", "DB1001.DBD2664" }, // Real
{ "3#深度", "DB1001.DBD2668" }, // Real
{ "3#角度", "DB1001.DBD2672" }, // Real
{ "3#拧紧时间", "DB1001.DBD2676" }, // Real
{ "5#扭矩", "DB1001.DBD2682" }, // Real
{ "5#深度", "DB1001.DBD2686" }, // Real
{ "5#角度", "DB1001.DBD2690" }, // Real
{ "5#拧紧时间", "DB1001.DBD2694" }, // Real
{ "6#扭矩", "DB1001.DBD2700" }, // Real
{ "6#深度", "DB1001.DBD2704" }, // Real
{ "6#角度", "DB1001.DBD2708" }, // Real
{ "6#拧紧时间", "DB1001.DBD2712" }, // Real
{ "1#扭矩", "DB1001.DBD2718" }, // Real
{ "1#深度", "DB1001.DBD2722" }, // Real
{ "1#角度", "DB1001.DBD2726" }, // Real
{ "1#拧紧时间", "DB1001.DBD2730" }, // Real
{ "2#扭矩", "DB1001.DBD2736" }, // Real
{ "2#深度", "DB1001.DBD2740" }, // Real
{ "2#角度", "DB1001.DBD2744" }, // Real
{ "2#拧紧时间", "DB1001.DBD2748" }, // Real
{ "4#扭矩", "DB1001.DBD2754" }, // Real
{ "4#深度", "DB1001.DBD2758" }, // Real
{ "4#角度", "DB1001.DBD2762" }, // Real
{ "4#拧紧时间", "DB1001.DBD2766" }, // Real
{ "7#扭矩", "DB1001.DBD2772" }, // Real
{ "7#深度", "DB1001.DBD2776" }, // Real
{ "7#角度", "DB1001.DBD2780" }, // Real
{ "7#拧紧时间", "DB1001.DBD2784" }, // Real
{ "节拍时间", "DB1001.DBD3518" } // Real
};
// OP110-3 专属地址映射盖板拧紧工位DB1001
private readonly Dictionary<string, (string Addr, int Len)> _op110_3StringMap = new()
{
{ "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte
{ "产品型号", ("DB1001.DBB1000", 48) }, // String[48]
{ "产品名称", ("DB1001.DBB1054", 48) }, // String[48]
{ "查询SN", ("DB1001.DBB2100", 28) }, // String[28]
{ "保存SN", ("DB1001.DBB2258", 28) } // String[28]
};
private readonly Dictionary<string, string> _op110_3IntMap = 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.DBW2288" }, // Int
{ "1#螺丝结果", "DB1001.DBW2290" }, // Int
{ "2#螺丝结果", "DB1001.DBW2308" }, // Int
{ "3#螺丝结果", "DB1001.DBW2326" }, // Int
{ "4#螺丝结果", "DB1001.DBW2344" }, // Int
{ "5#螺丝结果", "DB1001.DBW2362" }, // Int
{ "6#螺丝结果", "DB1001.DBW2380" }, // Int
{ "7#螺丝结果", "DB1001.DBW2398" }, // Int
// 螺丝工艺参数Real
{ "1#扭矩", "DB1001.DBD2292" }, // Real
{ "1#深度", "DB1001.DBD2296" }, // Real
{ "1#角度", "DB1001.DBD2300" }, // Real
{ "1#拧紧时间", "DB1001.DBD2304" }, // Real
{ "2#扭矩", "DB1001.DBD2310" }, // Real
{ "2#深度", "DB1001.DBD2314" }, // Real
{ "2#角度", "DB1001.DBD2318" }, // Real
{ "2#拧紧时间", "DB1001.DBD2322" }, // Real
{ "3#扭矩", "DB1001.DBD2328" }, // Real
{ "3#深度", "DB1001.DBD2332" }, // Real
{ "3#角度", "DB1001.DBD2336" }, // Real
{ "3#拧紧时间", "DB1001.DBD2340" }, // Real
{ "4#扭矩", "DB1001.DBD2346" }, // Real
{ "4#深度", "DB1001.DBD2350" }, // Real
{ "4#角度", "DB1001.DBD2354" }, // Real
{ "4#拧紧时间", "DB1001.DBD2358" }, // Real
{ "5#扭矩", "DB1001.DBD2364" }, // Real
{ "5#深度", "DB1001.DBD2368" }, // Real
{ "5#角度", "DB1001.DBD2372" }, // Real
{ "5#拧紧时间", "DB1001.DBD2376" }, // Real
{ "6#扭矩", "DB1001.DBD2382" }, // Real
{ "6#深度", "DB1001.DBD2386" }, // Real
{ "6#角度", "DB1001.DBD2390" }, // Real
{ "6#拧紧时间", "DB1001.DBD2394" }, // Real
{ "7#扭矩", "DB1001.DBD2400" }, // Real
{ "7#深度", "DB1001.DBD2404" }, // Real
{ "7#角度", "DB1001.DBD2408" }, // Real
{ "7#拧紧时间", "DB1001.DBD2412" }, // Real
{ "节拍时间", "DB1001.DBD3036" }, // Real
// 托盘号
{ "托盘号", "DB1001.DBW2072" } // Int
};
// OP115 专属地址映射自动上下料到固化炉工位DB1001
private readonly Dictionary<string, (string Addr, int Len)> _op115StringMap = new()
{
{ "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte
{ "产品型号", ("DB1001.DBB1000", 48) }, // String[48]
{ "产品名称", ("DB1001.DBB1054", 48) } // String[48]
};
private readonly Dictionary<string, string> _op115IntMap = 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=正常
};
// OP140 专属地址映射气密性测试工位DB1001
private readonly Dictionary<string, (string Addr, int Len)> _op140StringMap = new()
{
{ "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte
{ "产品型号", ("DB1001.DBB1000", 48) }, // String[48]
{ "产品名称", ("DB1001.DBB1054", 48) }, // String[48]
{ "查询SN", ("DB1001.DBB2146", 40) } // String[40]
};
private readonly Dictionary<string, string> _op140IntMap = 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=无请求
// 测试结果
{ "结果SN", "DB1001.DBW2260" }, // Int
{ "Socket", "DB1001.DBW2302" }, // Int - 1:工位12:工位2
{ "产品结果", "DB1001.DBW2304" }, // Int
{ "托盘号", "DB1001.DBW2318" }, // Int
// 工艺参数Real
{ "压力值", "DB1001.DBD2306" }, // Real
{ "泄露值", "DB1001.DBD2310" }, // Real
{ "节拍时间", "DB1001.DBD2314" } // Real
};
// OP165 专属地址映射自动贴标工位DB1001
private readonly Dictionary<string, (string Addr, int Len)> _op165StringMap = new()
{
{ "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte
{ "产品型号", ("DB1001.DBB1000", 48) }, // String[48]
{ "产品名称", ("DB1001.DBB1054", 48) }, // String[48]
{ "查询SN", ("DB1001.DBB2060", 40) }, // String[40]
{ "结果SN", ("DB1001.DBB2170", 40) }, // String[40]
{ "二维码内容", ("DB1001.DBB2226", 28) }, // String[28]
{ "下料工位条码", ("DB1001.DBB2876", 40) } // String[40]
};
private readonly Dictionary<string, string> _op165IntMap = 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.DBW2874" }, // Int
// 检测结果
{ "产品总结果", "DB1001.DBW2214" }, // Int
{ "轴承检测结果", "DB1001.DBW2216" }, // Int
{ "贴标拍照结果", "DB1001.DBW2218" }, // Int
{ "托盘号", "DB1001.DBW2220" }, // Int
// 工艺参数
{ "节拍时间", "DB1001.DBD2222" } // Real
};
#endregion
/// <summary>
/// 构造函数依赖注入获取PLC配置
/// </summary>
/// <param name="plcConfigs">所有PLC的连接配置</param>
/// <param name="globalConfig">PLC全局超时配置</param>
public PlcService(IOptions<GlobalPlcConfig> globalConfig)
{
_globalConfig = globalConfig?.Value ?? throw new ArgumentNullException(nameof(globalConfig), "PLC全局配置不能为空");
//初始化plcConfigs
_plcConfigs = initPlcConfigs(_plcConfigs);
}
#endregion
#region
/// <summary>
/// 读取PLC生产数据优化版连接池+并发控制+OP070-1/OP080专属适配
/// </summary>
/// <param name="ip">PLC IP地址</param>
/// <param name="plcName">PLC名称支持OP070-1/OP080</param>
/// <param name="rack">机架号</param>
/// <param name="slot">槽位号</param>
/// <param name="cpuType">PLC型号默认S7-1500</param>
/// <returns>读取结果(状态+数据+消息)</returns>
/// <summary>
/// PLC生产数据读取核心方法优化版
/// </summary>
/// <returns>成功状态/生产数据/提示消息</returns>
public async Task<(bool Success, PlcProductionData Data, string Message)> ReadProductionDataAsync(
string ip,
string plcName,
short rack,
short slot,
CpuType cpuType = CpuType.S71500)
{
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. 并发控制ConfigureAwait(false)减少线程上下文切换开销、提升异步执行效率
await _concurrencySemaphore.WaitAsync().ConfigureAwait(false);
try
{
// 3. 连接池复用+有效性校验(精简逻辑+轻量提效)
if (_plcConnPool.TryGetValue(poolKey, out var poolItem) && poolItem.Client is { IsConnected: true })
{
plc = poolItem.Client;
_plcConnPool[poolKey] = (plc, DateTime.Now);
isConnReused = true;
}
else
{
plc = CreatePlcClient(cpuType, ip, rack, slot);
await OpenPlcConnectionAsync(plc).ConfigureAwait(false);
if (!plc.IsConnected) return (false, null, $"{plcName}连接失败");
_plcConnPool.TryAdd(poolKey, (plc, DateTime.Now));
}
#region
//// 4. 多工位请求状态读取
//switch (plcName)
//{
// case "OP020-2":
// // 优化:异步读取取消上下文切换
// iSaveRequest = await ReadPlcIntAsync(plc, _op020_2IntMap["上传请求"]).ConfigureAwait(false);
// break;
// case "OP020-3":
// iSaveRequest = 1;
// break;
// case "OP020-4":
// // 核心优化4个地址并行读取耗时从累加和→最长单地址耗时
// var task4_1 = ReadPlcIntAsync(plc, _op020_4IntMap["产品1上传请求"]);
// var task4_2 = ReadPlcIntAsync(plc, _op020_4IntMap["产品2上传请求"]);
// var task4_3 = ReadPlcIntAsync(plc, _op020_4IntMap["产品3上传请求"]);
// var task4_4 = ReadPlcIntAsync(plc, _op020_4IntMap["产品4上传请求"]);
// // 并行等待所有任务完成(无编译错误)
// await Task.WhenAll(task4_1, task4_2, task4_3, task4_4).ConfigureAwait(false);
// iSaveRequest = (task4_1.Result == 1 || task4_2.Result == 1 || task4_3.Result == 1 || task4_4.Result == 1) ? 1 : 0;
// break;
// case "OP070-1":
// case "OP070-2":
// case "OP070-3":
// // 优化2个地址并行读取
// var taskQuery70 = ReadPlcIntAsync(plc, _op070_1IntMap["查询请求"]);
// var taskSave70 = ReadPlcIntAsync(plc, _op070_1IntMap["保存请求"]);
// await Task.WhenAll(taskQuery70, taskSave70).ConfigureAwait(false);
// iQueryRequest = taskQuery70.Result;
// iSaveRequest = taskSave70.Result;
// break;
// case "OP075":
// // 优化2个地址并行读取
// var taskQuery75 = ReadPlcIntAsync(plc, _op075IntMap["查询请求"]);
// var taskSave75 = ReadPlcIntAsync(plc, _op075IntMap["保存请求"]);
// await Task.WhenAll(taskQuery75, taskSave75).ConfigureAwait(false);
// iQueryRequest = taskQuery75.Result;
// iSaveRequest = taskSave75.Result;
// break;
// case "OP080-1":
// // 优化3个地址并行读取
// var taskQuery80 = ReadPlcIntAsync(plc, _op080_1IntMap["合装工位查询请求"]);
// var task8_1 = ReadPlcIntAsync(plc, _op080_1IntMap["合装结果保存请求"]);
// var task8_2 = ReadPlcIntAsync(plc, _op080_1IntMap["拧紧结果保存请求"]);
// await Task.WhenAll(taskQuery80, task8_1, task8_2).ConfigureAwait(false);
// iQueryRequest = taskQuery80.Result;
// if (task8_1.Result == 1) { iSaveRequest = 1; strSaveRequest = "合装结果保存请求"; }
// if (task8_2.Result == 1)
// {
// iSaveRequest = 1;
// strSaveRequest = string.IsNullOrEmpty(strSaveRequest)
// ? "拧紧结果保存请求"
// : $"{strSaveRequest},拧紧结果保存请求";
// }
// break;
//}
#endregion
// 4. 多工位请求状态读取
switch (plcName)
{
case "OP020-2":
iSaveRequest = await ReadPlcIntAsync(plc, _op020_2IntMap["上传请求"]).ConfigureAwait(false);
break;
case "OP020-3":
iSaveRequest = 1;
break;
case "OP020-4":
var task4_1 = ReadPlcIntAsync(plc, _op020_4IntMap["产品1上传请求"]);
var task4_2 = ReadPlcIntAsync(plc, _op020_4IntMap["产品2上传请求"]);
var task4_3 = ReadPlcIntAsync(plc, _op020_4IntMap["产品3上传请求"]);
var task4_4 = ReadPlcIntAsync(plc, _op020_4IntMap["产品4上传请求"]);
await Task.WhenAll(task4_1, task4_2, task4_3, task4_4).ConfigureAwait(false);
iSaveRequest = (task4_1.Result == 1 || task4_2.Result == 1 || task4_3.Result == 1 || task4_4.Result == 1) ? 1 : 0;
break;
case "OP050":
iSaveRequest = await ReadPlcIntAsync(plc, _op050IntMap["上传请求"]).ConfigureAwait(false);
break;
case "OP050-1":
iSaveRequest = 1;
break;
case "OP051扫码":
iSaveRequest = await ReadPlcIntAsync(plc, _op051ScanIntMap["上传结果请求"]).ConfigureAwait(false);
break;
case "OP057":
iSaveRequest = await ReadPlcIntAsync(plc, _op057IntMap["1#产品结果保存请求"]).ConfigureAwait(false);
break;
case "OP058":
iSaveRequest = 1;
break;
case "OP060":
iSaveRequest = await ReadPlcIntAsync(plc, _op060IntMap["1#产品结果保存请求"]).ConfigureAwait(false);
break;
case "OP070-1":
case "OP070-2":
case "OP070-3":
iSaveRequest = await ReadPlcIntAsync(plc, _op070_1IntMap["保存请求"]).ConfigureAwait(false);
break;
case "OP075":
iSaveRequest = await ReadPlcIntAsync(plc, _op075IntMap["保存请求"]).ConfigureAwait(false);
break;
case "OP080-1":
var task8_1 = ReadPlcIntAsync(plc, _op080_1IntMap["合装结果保存请求"]);
var task8_2 = ReadPlcIntAsync(plc, _op080_1IntMap["拧紧结果保存请求"]);
await Task.WhenAll(task8_1, task8_2).ConfigureAwait(false);
if (task8_1.Result == 1) { iSaveRequest = 1; strSaveRequest = "合装结果保存请求"; }
if (task8_2.Result == 1)
{
iSaveRequest = 1;
strSaveRequest = string.IsNullOrEmpty(strSaveRequest)
? "拧紧结果保存请求"
: $"{strSaveRequest},拧紧结果保存请求";
}
break;
case "OP080-2":
iSaveRequest = await ReadPlcIntAsync(plc, _op080_2IntMap["保存请求"]).ConfigureAwait(false);
break;
case "OP080-3":
iSaveRequest = await ReadPlcIntAsync(plc, _op080_3IntMap["保存请求"]).ConfigureAwait(false);
break;
case "OP085":
iSaveRequest = await ReadPlcIntAsync(plc, _op085IntMap["保存请求"]).ConfigureAwait(false);
break;
case "OP100":
iSaveRequest = await ReadPlcIntAsync(plc, _op100IntMap["保存请求"]).ConfigureAwait(false);
break;
case "OP1011":
iSaveRequest = await ReadPlcIntAsync(plc, _op1011IntMap["结果保存请求"]).ConfigureAwait(false);
break;
case "OP1012":
iSaveRequest = await ReadPlcIntAsync(plc, _op1012IntMap["结果保存请求"]).ConfigureAwait(false);
break;
case "OP102":
iSaveRequest = await ReadPlcIntAsync(plc, _op102IntMap["产品保存请求"]).ConfigureAwait(false);
break;
case "OP110-1":
iSaveRequest = await ReadPlcIntAsync(plc, _op110_1IntMap["产品保存请求"]).ConfigureAwait(false);
break;
case "OP110-2":
iSaveRequest = await ReadPlcIntAsync(plc, _op110_2IntMap["产品保存请求"]).ConfigureAwait(false);
break;
case "OP110-3":
iSaveRequest = await ReadPlcIntAsync(plc, _op110_3IntMap["产品保存请求"]).ConfigureAwait(false);
break;
case "OP115":
//iSaveRequest = await ReadPlcIntAsync(plc, _op115IntMap["结果保存请求"]).ConfigureAwait(false);
iSaveRequest = 1;
break;
case "OP140":
iSaveRequest = await ReadPlcIntAsync(plc, _op140IntMap["结果保存请求"]).ConfigureAwait(false);
break;
case "OP165":
iSaveRequest = await ReadPlcIntAsync(plc, _op165IntMap["结果保存请求"]).ConfigureAwait(false);
break;
}
if (iSaveRequest != 1) return (false, null, string.Empty);
if (iSaveRequest == 1)
{
// 优化:所有工位数据读取取消上下文切换
prodData = plcName switch
{
"OP020-2" => await ReadOP020_2DataAsync(plc, ip, plcName).ConfigureAwait(false),
"OP020-3" => await ReadOP020_3DataAsync(plc, ip, plcName).ConfigureAwait(false),
"OP020-4" => await ReadOP020_4DataAsync(plc, ip, plcName).ConfigureAwait(false),
"OP050" => await ReadOP050DataAsync(plc, ip, plcName).ConfigureAwait(false),
"OP050-1" => await ReadOP050_1DataAsync(plc, ip, plcName).ConfigureAwait(false),
"OP051扫码" => await ReadOP051ScanDataAsync(plc, ip, plcName).ConfigureAwait(false),
"OP057" => await ReadOP057DataAsync(plc, ip, plcName).ConfigureAwait(false),
"OP058" => await ReadOP058DataAsync(plc, ip, plcName).ConfigureAwait(false),
"OP060" => await ReadOP060DataAsync(plc, ip, plcName).ConfigureAwait(false),
"OP070-1" or "OP070-2" or "OP070-3" => await ReadOP070_1DataAsync(plc, ip, plcName).ConfigureAwait(false),
"OP075" => await ReadOP075DataAsync(plc, ip, plcName).ConfigureAwait(false),
"OP080-1" => await ReadOP080_1DataAsync(plc, ip, plcName, strSaveRequest).ConfigureAwait(false),
"OP080-2" => await ReadOP080_2DataAsync(plc, ip, plcName).ConfigureAwait(false),
"OP080-3" => await ReadOP080_3DataAsync(plc, ip, plcName).ConfigureAwait(false),
"OP085" => await ReadOP085DataAsync(plc, ip, plcName).ConfigureAwait(false),
"OP100" => await ReadOP100DataAsync(plc, ip, plcName).ConfigureAwait(false),
"OP1011" => await ReadOP1011DataAsync(plc, ip, plcName).ConfigureAwait(false),
"OP1012" => await ReadOP1012DataAsync(plc, ip, plcName).ConfigureAwait(false),
"OP102" => await ReadOP102DataAsync(plc, ip, plcName).ConfigureAwait(false),
"OP110-1" => await ReadOP110_1DataAsync(plc, ip, plcName).ConfigureAwait(false),
"OP110-2" => await ReadOP110_2DataAsync(plc, ip, plcName).ConfigureAwait(false),
"OP110-3" => await ReadOP110_3DataAsync(plc, ip, plcName).ConfigureAwait(false),
"OP115" => await ReadOP115DataAsync(plc, ip, plcName).ConfigureAwait(false),
"OP140" => await ReadOP140DataAsync(plc, ip, plcName).ConfigureAwait(false),
"OP165" => await ReadOP165DataAsync(plc, ip, plcName).ConfigureAwait(false),
_ => prodData
};
// 统一空值兜底(保留原逻辑)
if (prodData != null)
{
prodData.QualificationFlag ??= "0";
prodData.ReworkFlag ??= "0";
prodData.ProductionCycle ??= 0;
_ = Task.Run(() => _plcProductionDataService.AddPlcProductionData(prodData))
.ContinueWith(t =>
{
if (t.IsFaulted && plc is { IsConnected: true })
{
WritePlcSaveRequestResult(plc, ip, plcName, prodData, "6");
Console.WriteLine($"{plcName}({ip})数据保存失败:{t.Exception?.InnerException?.Message ?? t.Exception?.Message ?? ""}");
}
}, TaskContinuationOptions.OnlyOnFaulted)
.ConfigureAwait(false); // 新增:取消上下文切换
}
}
// 个性化返回消息+写入成功返回值
var successMsg = isConnReused
? $"{plcName}生产数据读取成功(复用连接)"
: $"{plcName}生产数据读取成功(新建连接)";
WritePlcSaveRequestResult(plc, ip, plcName, prodData, "1");
_ = Task.Run(() => RecordPlcOperationResult(plcName, prodData)).ConfigureAwait(false);
return (true, prodData, successMsg);
}
catch (Exception ex)
{
return (false, null, $"{plcName}生产数据读取失败:{ex.Message}");
}
finally
{
// 资源绝对释放:防止死锁+连接泄漏,增加多重校验
try
{
if (!isConnReused && plc != null)
{
ReleasePlcConnection(plc);
}
}
catch (Exception ex)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] PLC连接释放前置校验异常工位{plcName}IP{ip}{ex.Message}");
}
finally
{
// 确保信号量释放,无论任何情况
_concurrencySemaphore.Release();
}
}
}
#region
/// <summary>
/// 读取OP020-2数据合盖工位
/// </summary>
private async Task<PlcProductionData?> ReadOP020_2DataAsync(Plc plc, string ip, string workstationCode)
{
// 前置校验PLC连接无效直接返回避免无效操作
if (plc == null || !plc.IsConnected)
{
Console.WriteLine($"OP020-2({ip})PLC连接无效跳过数据读取");
return null;
}
try
{
// 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);
// 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["总结果"]);
// DInt任务单独提取避免字典开销
var taskActualOutput = ReadPlcIntAsync(plc, _op050IntMap["实际产量"]);
var taskQualifiedQty = ReadPlcIntAsync(plc, _op050IntMap["合格数量"]);
var taskFailedQty = ReadPlcIntAsync(plc, _op050IntMap["失败数量"]);
// 1.3 等待所有并行任务完成(关键:耗时=最慢的单个读取任务,而非总和)
await Task.WhenAll(
taskProductModel, taskProductName, taskSN,
taskRunStatus, taskMachineModel, taskOnlineStatus,
taskProduceModel, taskTrayNo, taskTotalResult, taskActualOutput, taskQualifiedQty, taskFailedQty);
// 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;
int actualOutput = await taskActualOutput;
int qualifiedQty = await taskQualifiedQty;
int failedQty = await taskFailedQty;
// 3. 异步复位上传请求(非阻塞,不影响数据读取效率)
_ = ResetUploadRequestAsync(plc, ip, _op020_2IntMap["上传请求"]);
// 4. 业务逻辑计算(优化:提前定义常量,减少重复计算)
string 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 = totalResult switch { 1 => "1", 2 => "0", _ => totalResult.ToString() };
// 5. 构建数据实体优化减少Trim/空值判断,提前兜底)
return new PlcProductionData
{
PlcIp = ip, // 提前确保ip非空无需Trim外层已校验
OccurTime = DateTime.Now,
LineCode = "line2",
WorkstationCode = workstationCode,
WorkstationName = "合盖", // 补充工站名称
ProductModel = productModel,
ProductName = productName,
ProductCode = sn,
SN1 = sn,
SN2 = sn,
QualificationFlag = qualificationFlag,
ReworkFlag = reworkFlag,
Automanual = machineModel,
Runstatus = runStatus,
OnlineStatus = onlineStatusDesc,
ProduceModel = produceModelDesc,
ActualOutQty = actualOutput.ToString(),
QualifiedQty = qualifiedQty.ToString(),
FailedQty = failedQty.ToString(),
TrayNo = trayNo.ToString(),
CreatedBy = "PLC",
CreatedTime = DateTime.Now
};
}
catch (Exception ex)
{
// 增强异常日志:包含堆栈,便于定位问题
Console.WriteLine($"OP020-2({ip})数据读取异常:{ex.Message}\n{ex.StackTrace}");
return null;
}
}
/// <summary>
/// OP020-3 数据读取热铆工位DB1001- 按OP020-4风格优化
/// </summary>
private async Task<PlcProductionData> ReadOP020_3DataAsync(Plc plc, string ip, string workstationCode)
{
// 前置校验PLC连接无效直接返回与OP020-4风格保持一致
if (plc == null || !plc.IsConnected)
{
return null;
}
try
{
// 1. 批量创建并行读取任务(字典存储,最大化并行效率,减少临时变量开销)
// 字符串读取任务匹配_op020_3StringMap所有字段
var stringReadTasks = new Dictionary<string, Task<string>>
{
{ "产品型号", ReadPlcStringAsync(plc, _op020_3StringMap["产品型号"].Addr, _op020_3StringMap["产品型号"].Len) },
{ "产品1SN", ReadPlcStringAsync(plc, _op020_3StringMap["产品1SN"].Addr, _op020_3StringMap["产品1SN"].Len) },
{ "产品2SN", ReadPlcStringAsync(plc, _op020_3StringMap["产品2SN"].Addr, _op020_3StringMap["产品2SN"].Len) },
{ "产品3SN", ReadPlcStringAsync(plc, _op020_3StringMap["产品3SN"].Addr, _op020_3StringMap["产品3SN"].Len) },
{ "产品4SN", ReadPlcStringAsync(plc, _op020_3StringMap["产品4SN"].Addr, _op020_3StringMap["产品4SN"].Len) }
};
// Int读取任务匹配_op020_3IntMap基础状态/请求/托盘号字段)
var intReadTasks = new Dictionary<string, Task<int>>
{
{ "运行状态", ReadPlcIntAsync(plc, _op020_3IntMap["运行状态"]) },
{ "设备模式", ReadPlcIntAsync(plc, _op020_3IntMap["设备模式"]) },
{ "设备在线状态", ReadPlcIntAsync(plc, _op020_3IntMap["设备在线状态"]) },
{ "ByPass", ReadPlcIntAsync(plc, _op020_3IntMap["ByPass"]) },
{ "生产模式", ReadPlcIntAsync(plc, _op020_3IntMap["生产模式"]) },
{ "查询请求", ReadPlcIntAsync(plc, _op020_3IntMap["查询请求"]) },
{ "上传请求", ReadPlcIntAsync(plc, _op020_3IntMap["上传请求"]) },
{ "托盘号", ReadPlcIntAsync(plc, _op020_3IntMap["托盘号"]) }
};
// DInt/Real读取任务产量+节拍时间复用ReadPlcIntAsync兼容转换与OP020-4风格一致
var dIntRealReadTasks = new Dictionary<string, Task<int>>
{
{ "节拍时间", ReadPlcIntAsync(plc, _op020_3IntMap["节拍时间"]) },
{ "合格数量", ReadPlcIntAsync(plc, _op020_3IntMap["合格数量"]) },
{ "失败数量", ReadPlcIntAsync(plc, _op020_3IntMap["失败数量"]) },
{ "实际数量", ReadPlcIntAsync(plc, _op020_3IntMap["实际数量"]) }
};
// 2. 并行等待所有读取任务完成合并任务列表单次WaitAll提升效率添加ConfigureAwait(false)优化异步)
var allTasks = new List<Task>();
allTasks.AddRange(stringReadTasks.Values);
allTasks.AddRange(intReadTasks.Values);
allTasks.AddRange(dIntRealReadTasks.Values);
await Task.WhenAll(allTasks).ConfigureAwait(false);
// 3. 提取读取结果(直接取值+空值兜底减少await重复调用与OP020-4风格一致
// 字符串字段
string productModel = stringReadTasks["产品型号"].Result ?? string.Empty;
string product1SN = stringReadTasks["产品1SN"].Result ?? string.Empty;
string product2SN = stringReadTasks["产品2SN"].Result ?? string.Empty;
string product3SN = stringReadTasks["产品3SN"].Result ?? string.Empty;
string product4SN = stringReadTasks["产品4SN"].Result ?? string.Empty;
// 整数字段
int runStatus = intReadTasks["运行状态"].Result;
int machineModel = intReadTasks["设备模式"].Result;
int onlineStatus = intReadTasks["设备在线状态"].Result;
int byPass = intReadTasks["ByPass"].Result;
int produceModel = intReadTasks["生产模式"].Result;
int trayNo = intReadTasks["托盘号"].Result;
// DInt/Real转换结果
int cycleTime = dIntRealReadTasks["节拍时间"].Result;
int qualifiedQty = dIntRealReadTasks["合格数量"].Result;
int failedQty = dIntRealReadTasks["失败数量"].Result;
int actualOutput = dIntRealReadTasks["实际数量"].Result;
// 4. 业务逻辑转换极简逻辑仅保留必要转换与OP020-4风格对齐
string reworkFlag = produceModel == 4 ? "1" : "0";
string produceModelDesc = produceModel switch
{
1 => "正常模式",
2 => "清线模式",
4 => "返工模式",
8 => "换型模式",
16 => "预热模式",
_ => produceModel.ToString()
};
string onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线";
// OP020-3无产品结果字段默认合格与原有逻辑保持一致
string qualificationFlag = "1";
// 5. 构建实体精准匹配PlcProductionData字段无冗余补充OP020-3独有信息
return new PlcProductionData
{
PlcIp = ip,
OccurTime = DateTime.Now,
LineCode = "line2",
WorkstationCode = workstationCode,
WorkstationName = "热铆工位", // 补充工站名称与OP020-4对齐
ProductModel = productModel,
ProductName = string.Empty, // OP020-3无产品名字段置空
ProductCode = product1SN, // 主产品编码取产品1SN与OP020-4对齐
ReworkFlag = reworkFlag,
Automanual = machineModel,
Runstatus = runStatus,
OnlineStatus = onlineStatusDesc,
ProduceModel = produceModelDesc,
TrayNo = trayNo.ToString(),
CreatedBy = "PLC",
CreatedTime = DateTime.Now,
Product1SN = product1SN,
Product2SN = product2SN,
Product3SN = product3SN,
Product4SN = product4SN,
SN1 = product1SN,
SN2 = product2SN,
ActualOutQty = actualOutput.ToString(),
QualifiedQty = qualifiedQty.ToString(),
FailedQty = failedQty.ToString(),
// 补充节拍时间和报警信息
ProductionCycle = cycleTime,
// 合格标识
QualificationFlag = qualificationFlag
};
}
catch
{
// 异常直接返回null与OP020-4风格保持一致
return null;
}
}
/// <summary>
/// 读取OP020-4数据pin压合&视觉检查工位)
/// </summary>
private async Task<PlcProductionData> ReadOP020_4DataAsync(Plc plc, string ip, string workstationCode)
{
// 前置校验PLC连接无效直接返回避免无效操作
if (plc == null || !plc.IsConnected)
{
return null;
}
try
{
// 1. 批量创建并行读取任务(最大化并行效率,减少临时变量开销)
var stringReadTasks = new Dictionary<string, Task<string>>
{
{ "报警信息", ReadPlcStringAsync(plc, _op020_4StringMap["报警信息"].Addr, _op020_4StringMap["报警信息"].Len) },
{ "产品型号", ReadPlcStringAsync(plc, _op020_4StringMap["产品型号"].Addr, _op020_4StringMap["产品型号"].Len) },
{ "产品名称", ReadPlcStringAsync(plc, _op020_4StringMap["产品名称"].Addr, _op020_4StringMap["产品名称"].Len) },
{ "产品1SN", ReadPlcStringAsync(plc, _op020_4StringMap["产品1SN"].Addr, _op020_4StringMap["产品1SN"].Len) },
{ "产品2SN", ReadPlcStringAsync(plc, _op020_4StringMap["产品2SN"].Addr, _op020_4StringMap["产品2SN"].Len) },
{ "产品3SN", ReadPlcStringAsync(plc, _op020_4StringMap["产品3SN"].Addr, _op020_4StringMap["产品3SN"].Len) },
{ "产品4SN", ReadPlcStringAsync(plc, _op020_4StringMap["产品4SN"].Addr, _op020_4StringMap["产品4SN"].Len) }
};
var intReadTasks = new Dictionary<string, Task<int>>
{
{ "运行状态", ReadPlcIntAsync(plc, _op020_4IntMap["运行状态"]) },
{ "设备模式", ReadPlcIntAsync(plc, _op020_4IntMap["设备模式"]) },
{ "设备在线状态", ReadPlcIntAsync(plc, _op020_4IntMap["设备在线状态"]) },
{ "ByPass", ReadPlcIntAsync(plc, _op020_4IntMap["ByPass"]) },
{ "生产模式", ReadPlcIntAsync(plc, _op020_4IntMap["生产模式"]) },
{ "托盘号", ReadPlcIntAsync(plc, _op020_4IntMap["托盘号"]) },
{ "产品1结果", ReadPlcIntAsync(plc, _op020_4IntMap["产品1结果"]) },
{ "产品2结果", ReadPlcIntAsync(plc, _op020_4IntMap["产品2结果"]) },
{ "产品3结果", ReadPlcIntAsync(plc, _op020_4IntMap["产品3结果"]) },
{ "产品4结果", ReadPlcIntAsync(plc, _op020_4IntMap["产品4结果"]) }
};
// DInt双整数读取任务复用ReadPlcIntAsyncPLC底层兼容DInt转int
var dIntReadTasks = new Dictionary<string, Task<int>>
{
{ "实际产量", ReadPlcIntAsync(plc, _op050IntMap["实际产量"]) },
{ "合格数量", ReadPlcIntAsync(plc, _op050IntMap["合格数量"]) },
{ "失败数量", ReadPlcIntAsync(plc, _op050IntMap["失败数量"]) }
};
// 2. 并行等待所有读取任务完成合并任务列表单次WaitAll提升效率
var allTasks = new List<Task>();
allTasks.AddRange(stringReadTasks.Values);
allTasks.AddRange(intReadTasks.Values);
allTasks.AddRange(dIntReadTasks.Values);
await Task.WhenAll(allTasks).ConfigureAwait(false);
// 3. 提取读取结果(直接取值+空值兜底减少await重复调用
// 字符串字段
string productModel = stringReadTasks["产品型号"].Result ?? string.Empty;
string productName = stringReadTasks["产品名称"].Result ?? string.Empty;
string product1SN = stringReadTasks["产品1SN"].Result ?? string.Empty;
string product2SN = stringReadTasks["产品2SN"].Result ?? string.Empty;
string product3SN = stringReadTasks["产品3SN"].Result ?? string.Empty;
string product4SN = stringReadTasks["产品4SN"].Result ?? string.Empty;
// 整数字段
int runStatus = intReadTasks["运行状态"].Result;
int machineModel = intReadTasks["设备模式"].Result;
int onlineStatus = intReadTasks["设备在线状态"].Result;
int produceModel = intReadTasks["生产模式"].Result;
int trayNo = intReadTasks["托盘号"].Result;
int product1Result = intReadTasks["产品1结果"].Result;
int product2Result = intReadTasks["产品2结果"].Result;
int product3Result = intReadTasks["产品3结果"].Result;
int product4Result = intReadTasks["产品4结果"].Result;
int actualOutput = dIntReadTasks["实际产量"].Result;
int qualifiedQty = dIntReadTasks["合格数量"].Result;
int failedQty = dIntReadTasks["失败数量"].Result;
// 4. 业务逻辑转换(极简逻辑,仅保留必要转换)
string reworkFlag = produceModel == 4 ? "1" : "0";
string produceModelDesc = produceModel switch
{
1 => "正常模式",
2 => "清线模式",
4 => "返工模式",
8 => "换型模式",
16 => "预热模式",
_ => produceModel.ToString()
};
string onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线";
bool allProductsOk = product1Result == 1 && product2Result == 1 && product3Result == 1 && product4Result == 1;
string qualificationFlag = allProductsOk ? "1" : "2";
// 6. 构建实体精准匹配PlcProductionData字段无冗余
return new PlcProductionData
{
PlcIp = ip,
OccurTime = DateTime.Now,
LineCode = "line2",
WorkstationCode = workstationCode,
WorkstationName = "pin压合&视觉检查", // 补充工站名称
ProductModel = productModel,
ProductName = productName,
ProductCode = product1SN, // 主产品编码取产品1SN可根据业务调整
ReworkFlag = reworkFlag,
Automanual = machineModel,
Runstatus = runStatus,
OnlineStatus = onlineStatusDesc,
ProduceModel = produceModelDesc,
TrayNo = trayNo.ToString(),
CreatedBy = "PLC",
CreatedTime = DateTime.Now,
Product1SN = product1SN,
Product2SN = product2SN,
Product3SN = product3SN,
Product4SN = product4SN,
Product1Result = product1Result.ToString(),
Product2Result = product2Result.ToString(),
Product3Result = product1Result.ToString(),
Product4Result = product1Result.ToString(),
SN1 = product1SN,
SN2 = product2SN,
ActualOutQty = actualOutput.ToString(),
QualifiedQty = qualifiedQty.ToString(),
FailedQty = failedQty.ToString(),
QualificationFlag = qualificationFlag
};
}
catch
{
return null;
}
}
/// <summary>
/// 读取OP050数据点白胶DC744工位
/// </summary>
/// <param name="plc">PLC连接实例</param>
/// <param name="ip">PLC的IP地址</param>
/// <param name="workstationCode">工位编码</param>
/// <returns>PLC生产数据实体</returns>
private async Task<PlcProductionData> ReadOP050DataAsync(Plc plc, string ip, string workstationCode)
{
// 前置校验PLC连接无效直接返回避免无效操作
if (plc == null || !plc.IsConnected)
{
return null;
}
try
{
// 1. 批量创建并行读取任务(最大化并行效率,按字段类型分类)
var stringReadTasks = new Dictionary<string, Task<string>>
{
{ "报警信息", ReadPlcStringAsync(plc, _op050StringMap["报警信息"].Addr, _op050StringMap["报警信息"].Len) },
{ "产品型号", ReadPlcStringAsync(plc, _op050StringMap["产品型号"].Addr, _op050StringMap["产品型号"].Len) },
{ "产品名称", ReadPlcStringAsync(plc, _op050StringMap["产品名称"].Addr, _op050StringMap["产品名称"].Len) },
{ "产品1SN", ReadPlcStringAsync(plc, _op050StringMap["产品1SN"].Addr, _op050StringMap["产品1SN"].Len) },
{ "产品2SN", ReadPlcStringAsync(plc, _op050StringMap["产品2SN"].Addr, _op050StringMap["产品2SN"].Len) },
{ "产品3SN", ReadPlcStringAsync(plc, _op050StringMap["产品3SN"].Addr, _op050StringMap["产品3SN"].Len) },
{ "产品4SN", ReadPlcStringAsync(plc, _op050StringMap["产品4SN"].Addr, _op050StringMap["产品4SN"].Len) }
};
// 注意OP050包含DInt/Real类型需适配读取方法假设已有对应异步方法
var intReadTasks = new Dictionary<string, Task<int>>
{
{ "运行状态", ReadPlcIntAsync(plc, _op050IntMap["运行状态"]) },
{ "设备模式", ReadPlcIntAsync(plc, _op050IntMap["设备模式"]) },
{ "设备在线状态", ReadPlcIntAsync(plc, _op050IntMap["设备在线状态"]) },
{ "ByPass", ReadPlcIntAsync(plc, _op050IntMap["ByPass"]) },
{ "生产模式", ReadPlcIntAsync(plc, _op050IntMap["生产模式"]) },
{ "托盘号", ReadPlcIntAsync(plc, _op050IntMap["托盘号"]) }
};
// DInt双整数读取任务复用ReadPlcIntAsyncPLC底层兼容DInt转int
var dIntReadTasks = new Dictionary<string, Task<int>>
{
{ "实际产量", ReadPlcIntAsync(plc, _op050IntMap["实际产量"]) },
{ "合格数量", ReadPlcIntAsync(plc, _op050IntMap["合格数量"]) },
{ "失败数量", ReadPlcIntAsync(plc, _op050IntMap["失败数量"]) }
};
// Real浮点型读取任务新增ReadPlcRealAsync方法返回float
var realReadTasks = new Dictionary<string, Task<float>>
{
{ "节拍时间", ReadPlcRealAsync(plc, _op050IntMap["节拍时间"]) }
};
// 2. 并行等待所有读取任务完成合并所有任务列表单次WaitAll提升效率
var allTasks = new List<Task>();
allTasks.AddRange(stringReadTasks.Values);
allTasks.AddRange(intReadTasks.Values);
allTasks.AddRange(dIntReadTasks.Values);
allTasks.AddRange(realReadTasks.Values);
await Task.WhenAll(allTasks).ConfigureAwait(false);
// 3. 提取读取结果(直接取值+空值兜底,任务已完成无阻塞风险)
// 字符串字段
string productModel = stringReadTasks["产品型号"].Result ?? string.Empty;
string productName = stringReadTasks["产品名称"].Result ?? string.Empty;
string product1SN = stringReadTasks["产品1SN"].Result ?? string.Empty;
string product2SN = stringReadTasks["产品2SN"].Result ?? string.Empty;
string product3SN = stringReadTasks["产品3SN"].Result ?? string.Empty;
string product4SN = stringReadTasks["产品4SN"].Result ?? string.Empty;
// 整数/双整数字段
int runStatus = intReadTasks["运行状态"].Result;
int machineModel = intReadTasks["设备模式"].Result;
int onlineStatus = intReadTasks["设备在线状态"].Result;
int byPass = intReadTasks["ByPass"].Result;
int produceModel = intReadTasks["生产模式"].Result;
int trayNo = intReadTasks["托盘号"].Result;
int actualOutput = dIntReadTasks["实际产量"].Result;
int qualifiedQty = dIntReadTasks["合格数量"].Result;
int failedQty = dIntReadTasks["失败数量"].Result;
// 浮点数字段
float cycleTime = realReadTasks["节拍时间"].Result;
// 5. 业务逻辑转换(极简+严谨)
string reworkFlag = produceModel == 4 ? "1" : "0";
string produceModelDesc = produceModel switch
{
1 => "正常模式",
2 => "清线模式",
4 => "返工模式",
8 => "换型模式",
16 => "预热模式",
_ => produceModel.ToString()
};
string onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线";
// OP050无单个产品结果合格标识按总产量逻辑有失败则NG(2)否则OK(1)
bool allQualified = failedQty == 0 && actualOutput >= 0;
string qualificationFlag = "1";
// 6. 构建实体精准匹配PlcProductionData字段适配OP050特性
return new PlcProductionData
{
PlcIp = ip,
OccurTime = DateTime.Now,
LineCode = "line2", // 按实际产线调整,建议后续改为参数
WorkstationCode = workstationCode,
WorkstationName = "点白胶DC744", // 补充工站名称
ProductModel = productModel,
ProductName = productName,
ProductCode = product1SN, // 主产品编码取产品1SN
ReworkFlag = reworkFlag,
Automanual = machineModel,
Runstatus = runStatus,
OnlineStatus = onlineStatusDesc,
ProduceModel = produceModelDesc,
TrayNo = trayNo.ToString(),
CreatedBy = "PLC",
CreatedTime = DateTime.Now,
// 4个产品SN匹配实体字段
Product1SN = product1SN,
Product2SN = product2SN,
Product3SN = product3SN,
Product4SN = product4SN,
ActualOutQty = actualOutput.ToString(),
QualifiedQty = qualifiedQty.ToString(),
FailedQty = failedQty.ToString(),
// 兼容原有SN字段
SN1 = product1SN,
SN2 = product2SN,
// OP050核心产量/节拍字段
ProductionCycle = (int)Math.Round(cycleTime), // 节拍时间转整数秒
QualificationFlag = qualificationFlag,
};
}
catch
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] OP050读取异常");
return null;
}
}
/// <summary>
/// 读取OP050-1数据自动下料工位DB1001
/// </summary>
private async Task<PlcProductionData> ReadOP050_1DataAsync(Plc plc, string ip, string workstationCode)
{
// 前置校验PLC连接无效直接返回避免无效操作
if (plc == null || !plc.IsConnected)
{
return null;
}
try
{
// 1. 批量创建并行读取任务(按字段类型分类,最大化并行效率)
var stringReadTasks = new Dictionary<string, Task<string>>
{
{ "报警信息", ReadPlcStringAsync(plc, _op050_1StringMap["报警信息"].Addr, _op050_1StringMap["报警信息"].Len) },
{ "产品型号", ReadPlcStringAsync(plc, _op050_1StringMap["产品型号"].Addr, _op050_1StringMap["产品型号"].Len) },
{ "产品名称", ReadPlcStringAsync(plc, _op050_1StringMap["产品名称"].Addr, _op050_1StringMap["产品名称"].Len) }
};
var intReadTasks = new Dictionary<string, Task<int>>
{
{ "运行状态", ReadPlcIntAsync(plc, _op050_1IntMap["运行状态"]) },
{ "设备模式", ReadPlcIntAsync(plc, _op050_1IntMap["设备模式"]) },
{ "设备在线状态", ReadPlcIntAsync(plc, _op050_1IntMap["设备在线状态"]) },
{ "ByPass", ReadPlcIntAsync(plc, _op050_1IntMap["ByPass"]) },
{ "生产模式", ReadPlcIntAsync(plc, _op050_1IntMap["生产模式"]) }
};
// DInt双整数读取任务产量相关
var dIntReadTasks = new Dictionary<string, Task<int>>
{
{ "实际产量", ReadPlcIntAsync(plc, _op050_1IntMap["实际产量"]) },
{ "合格数量", ReadPlcIntAsync(plc, _op050_1IntMap["合格数量"]) },
{ "失败数量", ReadPlcIntAsync(plc, _op050_1IntMap["失败数量"]) }
};
// Real浮点型读取任务节拍时间
var realReadTasks = new Dictionary<string, Task<float>>
{
{ "节拍时间", ReadPlcRealAsync(plc, _op050_1IntMap["节拍时间"]) }
};
// 2. 并行等待所有读取任务完成单次WaitAll最小化等待时间
var allTasks = new List<Task>();
allTasks.AddRange(stringReadTasks.Values);
allTasks.AddRange(intReadTasks.Values);
allTasks.AddRange(dIntReadTasks.Values);
allTasks.AddRange(realReadTasks.Values);
await Task.WhenAll(allTasks).ConfigureAwait(false);
// 3. 提取读取结果(直接取值+空值兜底,无阻塞风险)
// 字符串字段
string productModel = stringReadTasks["产品型号"].Result ?? string.Empty;
string productName = stringReadTasks["产品名称"].Result ?? string.Empty;
// 整数基础状态字段
int runStatus = intReadTasks["运行状态"].Result;
int machineModel = intReadTasks["设备模式"].Result;
int onlineStatus = intReadTasks["设备在线状态"].Result;
int produceModel = intReadTasks["生产模式"].Result;
// 产量相关字段DInt
int actualOutput = dIntReadTasks["实际产量"].Result;
int qualifiedQty = dIntReadTasks["合格数量"].Result;
int failedQty = dIntReadTasks["失败数量"].Result;
// 节拍时间Real
float cycleTime = realReadTasks["节拍时间"].Result;
// 4. 业务逻辑转换(极简+严谨)
string reworkFlag = produceModel == 4 ? "1" : "0"; // 返工模式标识
string produceModelDesc = produceModel switch
{
1 => "正常模式",
2 => "清线模式",
4 => "返工模式",
8 => "换型模式",
16 => "预热模式",
_ => produceModel.ToString()
};
string onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线";
// 合格标识失败数量为0且实际产量≥0则OK(1)否则NG(2)
bool allQualified = failedQty == 0 && actualOutput >= 0;
string qualificationFlag = allQualified ? "1" : "2";
// 5. 构建实体精准匹配PlcProductionData字段无冗余
return new PlcProductionData
{
PlcIp = ip,
OccurTime = DateTime.Now,
LineCode = "line2", // 按实际产线调整,建议改为参数
WorkstationName = "自动下料", // 补充工站名称
WorkstationCode = workstationCode,
ProductModel = productModel,
ProductName = productName,
ProductCode = string.Empty,
ReworkFlag = reworkFlag,
Automanual = machineModel,
Runstatus = runStatus,
OnlineStatus = onlineStatusDesc,
ProduceModel = produceModelDesc,
TrayNo = string.Empty,
CreatedBy = "PLC",
CreatedTime = DateTime.Now,
ActualOutQty = actualOutput.ToString(),
QualifiedQty = qualifiedQty.ToString(),
FailedQty = failedQty.ToString(),
ProductionCycle = (int)Math.Round(cycleTime), // 节拍时间转整数秒
QualificationFlag = qualificationFlag,
// 备注记录产量信息(便于排查)
Remark = $"实际产量:{actualOutput},合格数量:{qualifiedQty},失败数量:{failedQty},节拍时间:{cycleTime:F2}秒"
};
}
catch(Exception ex)
{
// 异常静默处理返回null避免上层崩溃
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] OP050_1读取异常{ex.Message}");
return null;
}
}
/// <summary>
/// 读取OP051扫码工位数据适配Coating扫码业务无冗余逻辑
/// </summary>
/// <param name="plc">PLC连接实例</param>
/// <param name="ip">PLC IP地址</param>
/// <param name="workstationCode">工位编码如OP051</param>
/// <returns>PLC生产数据实体</returns>
public async Task<PlcProductionData> ReadOP051ScanDataAsync(Plc plc, string ip, string workstationCode)
{
if (plc == null || !plc.IsConnected) return null;
if (string.IsNullOrWhiteSpace(ip)) throw new ArgumentNullException(nameof(ip), "PLC IP地址不能为空");
if (string.IsNullOrWhiteSpace(workstationCode)) throw new ArgumentNullException(nameof(workstationCode), "工位编码不能为空");
try
{
// 1. 批量创建并行读取任务(按类型分类,最大化并行效率)
var stringTasks = new Dictionary<string, Task<string>>
{
{ "产品型号", ReadPlcStringAsync(plc, _op051ScanStringMap["产品型号"].Addr, _op051ScanStringMap["产品型号"].Len) },
{ "产品名称", ReadPlcStringAsync(plc, _op051ScanStringMap["产品名称"].Addr, _op051ScanStringMap["产品名称"].Len) },
{ "SN_1", ReadPlcStringAsync(plc, _op051ScanStringMap["SN_1"].Addr, _op051ScanStringMap["SN_1"].Len) },
{ "SN_2", ReadPlcStringAsync(plc, _op051ScanStringMap["SN_2"].Addr, _op051ScanStringMap["SN_2"].Len) },
{ "SN_3", ReadPlcStringAsync(plc, _op051ScanStringMap["SN_3"].Addr, _op051ScanStringMap["SN_3"].Len) }
};
var intTasks = new Dictionary<string, Task<int>>
{
{ "运行状态", ReadPlcIntAsync(plc, _op051ScanIntMap["运行状态"]) },
{ "设备模式", ReadPlcIntAsync(plc, _op051ScanIntMap["设备模式"]) },
{ "设备在线状态", ReadPlcIntAsync(plc, _op051ScanIntMap["设备在线状态"]) },
{ "生产模式", ReadPlcIntAsync(plc, _op051ScanIntMap["生产模式"]) },
{ "查询请求", ReadPlcIntAsync(plc, _op051ScanIntMap["查询请求"]) },
{ "上传结果请求", ReadPlcIntAsync(plc, _op051ScanIntMap["上传结果请求"]) },
{ "托盘号", ReadPlcIntAsync(plc, _op051ScanIntMap["托盘号"]) }
};
// DInt双整数读取任务复用ReadPlcIntAsyncPLC底层兼容DInt转int
var dIntReadTasks = new Dictionary<string, Task<int>>
{
{ "实际产量", ReadPlcIntAsync(plc, _op050IntMap["实际产量"]) },
{ "合格数量", ReadPlcIntAsync(plc, _op050IntMap["合格数量"]) },
{ "失败数量", ReadPlcIntAsync(plc, _op050IntMap["失败数量"]) }
};
// 2. 并行等待所有任务完成单次WaitAll最小化等待时间
var allTasks = new List<Task>();
allTasks.AddRange(stringTasks.Values);
allTasks.AddRange(dIntReadTasks.Values);
allTasks.AddRange(intTasks.Values);
await Task.WhenAll(allTasks).ConfigureAwait(false);
// 3. 提取结果(直接取值,空值兜底,减少内存分配)
var now = DateTime.Now; // 单次获取时间,减少系统调用
var productModel = stringTasks["产品型号"].Result;
var productName = stringTasks["产品名称"].Result;
var sn1 = stringTasks["SN_1"].Result;
var sn2 = stringTasks["SN_2"].Result;
var sn3 = stringTasks["SN_3"].Result;
var runStatus = intTasks["运行状态"].Result;
var machineModel = intTasks["设备模式"].Result;
var onlineStatus = intTasks["设备在线状态"].Result;
var produceModel = intTasks["生产模式"].Result;
var queryRequest = intTasks["查询请求"].Result;
var uploadRequest = intTasks["上传结果请求"].Result;
var trayNo = intTasks["托盘号"].Result.ToString(); // 转换为字符串,适配实体字段
int actualOutput = dIntReadTasks["实际产量"].Result;
int qualifiedQty = dIntReadTasks["合格数量"].Result;
int failedQty = dIntReadTasks["失败数量"].Result;
// 4. 核心逻辑转换(极简表达式,适配扫码工位业务)
var reworkFlag = produceModel == 4 ? "1" : "0"; // 4=返工模式→1其他→0
var produceModelDesc = produceModel switch
{
1 => "正常模式",
2 => "清线模式",
4 => "返工模式",
8 => "换型模式",
16 => "预热模式",
_ => $"未知模式({produceModel})"
};
var onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线";
var queryRequestDesc = queryRequest != 0 ? "有查询请求" : "无查询请求";
var uploadRequestDesc = uploadRequest != 0 ? "有上传请求" : "无上传请求";
var qualificationFlag = "1"; // 扫码工位默认合格(无检测结果,可根据业务调整)
// 6. 构建并返回实体(适配扫码工位特性,精简字段)
return new PlcProductionData
{
PlcIp = ip,
OccurTime = now,
LineCode = "line2", // 可改为参数传入
WorkstationCode = workstationCode,
WorkstationName = "Coating扫码", // 补充工站名称
ProductModel = productModel,
ProductName = productName,
ProductCode = sn2, // 主SN用SN_1
ReworkFlag = reworkFlag,
Automanual = machineModel,
Runstatus = runStatus,
OnlineStatus = onlineStatusDesc,
ProduceModel = produceModelDesc,
TrayNo = trayNo,
SN1 = sn1,
SN2 = sn2,
Product1SN = sn1,
Product2SN = sn2,
Product3SN = sn3,
QualificationFlag = qualificationFlag,
ActualOutQty = actualOutput.ToString(),
QualifiedQty = qualifiedQty.ToString(),
FailedQty = failedQty.ToString(),
CreatedBy = "PLC",
CreatedTime = now,
};
}
catch (Exception ex)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] OP051扫码工位读取异常{ex.Message}");
return null;
}
}
/// <summary>
/// 读取OP057数据压装定位销&激光打标工位DB1001
/// </summary>
private async Task<PlcProductionData> ReadOP057DataAsync(Plc plc, string ip, string workstationCode)
{
// 前置校验PLC连接无效直接返回
if (plc == null || !plc.IsConnected)
{
return null;
}
try
{
// 1. 批量创建并行读取任务
var stringReadTasks = new Dictionary<string, Task<string>>
{
{ "报警信息", ReadPlcStringAsync(plc, _op057StringMap["报警信息"].Addr, _op057StringMap["报警信息"].Len) },
{ "产品型号", ReadPlcStringAsync(plc, _op057StringMap["产品型号"].Addr, _op057StringMap["产品型号"].Len) },
{ "产品名称", ReadPlcStringAsync(plc, _op057StringMap["产品名称"].Addr, _op057StringMap["产品名称"].Len) },
{ "SN_1", ReadPlcStringAsync(plc, _op057StringMap["SN_1"].Addr, _op057StringMap["SN_1"].Len) },
{ "SN_2", ReadPlcStringAsync(plc, _op057StringMap["SN_2"].Addr, _op057StringMap["SN_2"].Len) }
};
var intReadTasks = new Dictionary<string, Task<int>>
{
{ "运行状态", ReadPlcIntAsync(plc, _op057IntMap["运行状态"]) },
{ "设备模式", ReadPlcIntAsync(plc, _op057IntMap["设备模式"]) },
{ "设备在线状态", ReadPlcIntAsync(plc, _op057IntMap["设备在线状态"]) },
{ "ByPass", ReadPlcIntAsync(plc, _op057IntMap["ByPass"]) },
{ "生产模式", ReadPlcIntAsync(plc, _op057IntMap["生产模式"]) },
{ "产品总结果", ReadPlcIntAsync(plc, _op057IntMap["产品总结果"]) },
{ "1#销结果", ReadPlcIntAsync(plc, _op057IntMap["1#销结果"]) },
{ "2#销结果", ReadPlcIntAsync(plc, _op057IntMap["2#销结果"]) }
};
var dIntReadTasks = new Dictionary<string, Task<int>>
{
{ "实际产量", ReadPlcIntAsync(plc, _op057IntMap["实际产量"]) },
{ "合格数量", ReadPlcIntAsync(plc, _op057IntMap["合格数量"]) },
{ "失败数量", ReadPlcIntAsync(plc, _op057IntMap["失败数量"]) }
};
var realReadTasks = new Dictionary<string, Task<float>>
{
{ "1#销压力", ReadPlcRealAsync(plc, _op057IntMap["1#销压力"]) },
{ "1#销行程", ReadPlcRealAsync(plc, _op057IntMap["1#销行程"]) },
{ "2#销压力", ReadPlcRealAsync(plc, _op057IntMap["2#销压力"]) },
{ "2#销行程", ReadPlcRealAsync(plc, _op057IntMap["2#销行程"]) },
{ "节拍时间", ReadPlcRealAsync(plc, _op057IntMap["节拍时间"]) }
};
// 2. 并行等待所有读取任务完成
var allTasks = new List<Task>();
allTasks.AddRange(stringReadTasks.Values);
allTasks.AddRange(intReadTasks.Values);
allTasks.AddRange(dIntReadTasks.Values);
allTasks.AddRange(realReadTasks.Values);
await Task.WhenAll(allTasks).ConfigureAwait(false);
// 3. 提取读取结果
string productModel = stringReadTasks["产品型号"].Result ?? string.Empty;
string productName = stringReadTasks["产品名称"].Result ?? string.Empty;
string sn1 = stringReadTasks["SN_1"].Result ?? string.Empty;
string sn2 = stringReadTasks["SN_2"].Result ?? string.Empty;
int runStatus = intReadTasks["运行状态"].Result;
int machineModel = intReadTasks["设备模式"].Result;
int onlineStatus = intReadTasks["设备在线状态"].Result;
int produceModel = intReadTasks["生产模式"].Result;
int productTotalResult = intReadTasks["产品总结果"].Result;
int pin1Result = intReadTasks["1#销结果"].Result;
int pin2Result = intReadTasks["2#销结果"].Result;
int actualOutput = dIntReadTasks["实际产量"].Result;
int qualifiedQty = dIntReadTasks["合格数量"].Result;
int failedQty = dIntReadTasks["失败数量"].Result;
float pin1Pressure = realReadTasks["1#销压力"].Result;
float pin1Stroke = realReadTasks["1#销行程"].Result;
float pin2Pressure = realReadTasks["2#销压力"].Result;
float pin2Stroke = realReadTasks["2#销行程"].Result;
float cycleTime = realReadTasks["节拍时间"].Result;
// 4. 业务逻辑转换
string reworkFlag = produceModel == 2 ? "1" : "0";
string produceModelDesc = produceModel switch
{
1 => "点检模式",
2 => "返工模式",
4 => "样件模式",
5 => "正常模式",
_ => produceModel.ToString()
};
string onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线";
string qualificationFlag = productTotalResult == 1 ? "1" : "2";
// 5. 构建实体
return new PlcProductionData
{
PlcIp = ip,
OccurTime = DateTime.Now,
LineCode = "line2",
WorkstationCode = workstationCode,
WorkstationName = "压装定位销&激光打标", // 补充工站名称
ProductModel = productModel,
ProductName = productName,
ProductCode = sn1,
ReworkFlag = reworkFlag,
Automanual = machineModel,
Runstatus = runStatus,
OnlineStatus = onlineStatusDesc,
ProduceModel = produceModelDesc,
PinPressure1 = pin1Pressure.ToString(),
PinStroke1 = pin1Stroke.ToString(),
PinPressure2 = pin2Pressure.ToString(),
PinStroke2 = pin2Stroke.ToString(),
CreatedBy = "PLC",
CreatedTime = DateTime.Now,
SN1 = sn1,
SN2 = sn2,
Product1SN = sn1,
Product2SN = sn2,
Product1Result = pin1Result.ToString(),
Product2Result = pin2Result.ToString(),
QualificationFlag = qualificationFlag,
ActualOutQty = actualOutput.ToString(),
QualifiedQty = qualifiedQty.ToString(),
FailedQty = failedQty.ToString(),
ProductionCycle = (int)Math.Round(cycleTime),
};
}
catch (Exception ex)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] OP057读取异常{ex.Message}");
return null;
}
}
/// <summary>
/// 读取OP058数据压装定位销&激光打标工位)
/// </summary>
public async Task<PlcProductionData> ReadOP058DataAsync(Plc plc, string ip, string workstationCode)
{
// 前置校验:快速失败
if (plc == null || !plc.IsConnected) return null;
if (string.IsNullOrWhiteSpace(ip) || string.IsNullOrWhiteSpace(workstationCode))
throw new ArgumentNullException("IP或工位编码不能为空");
try
{
// 1. 批量创建并行读取任务
var stringTasks = new Dictionary<string, Task<string>>
{
{ "产品型号", ReadPlcStringAsync(plc, _op058StringMap["产品型号"].Addr, _op058StringMap["产品型号"].Len) },
{ "产品名称", ReadPlcStringAsync(plc, _op058StringMap["产品名称"].Addr, _op058StringMap["产品名称"].Len) },
{ "SN_1", ReadPlcStringAsync(plc, _op058StringMap["SN_1"].Addr, _op058StringMap["SN_1"].Len) }
};
var intTasks = new Dictionary<string, Task<int>>
{
{ "实际产量", ReadPlcIntAsync(plc, _op058IntMap["实际产量"]) },
{ "合格数量", ReadPlcIntAsync(plc, _op058IntMap["合格数量"]) },
{ "失败数量", ReadPlcIntAsync(plc, _op058IntMap["失败数量"]) },
{ "产品总结果", ReadPlcIntAsync(plc, _op058IntMap["产品总结果"]) },
{ "结果", ReadPlcIntAsync(plc, _op058IntMap["结果"]) }
};
var realTasks = new Dictionary<string, Task<float>>
{
{ "压力", ReadPlcRealAsync(plc, _op058IntMap["压力"]) },
{ "行程", ReadPlcRealAsync(plc, _op058IntMap["行程"]) },
{ "节拍时间", ReadPlcRealAsync(plc, _op058IntMap["节拍时间"]) }
};
// 2. 并行等待所有任务完成
var allTasks = new List<Task>();
allTasks.AddRange(stringTasks.Values);
allTasks.AddRange(intTasks.Values);
allTasks.AddRange(realTasks.Values);
await Task.WhenAll(allTasks).ConfigureAwait(false);
// 3. 提取结果
var now = DateTime.Now;
var productModel = stringTasks["产品型号"].Result ?? string.Empty;
var productName = stringTasks["产品名称"].Result ?? string.Empty;
var sn1 = stringTasks["SN_1"].Result ?? string.Empty;
var actualOutput = intTasks["实际产量"].Result;
var qualifiedQty = intTasks["合格数量"].Result;
var failedQty = intTasks["失败数量"].Result;
var productTotalResult = intTasks["产品总结果"].Result;
var result = intTasks["结果"].Result;
var pressure = realTasks["压力"].Result;
var stroke = realTasks["行程"].Result;
var cycleTime = realTasks["节拍时间"].Result;
// 4. 业务逻辑转换
var qualificationFlag = productTotalResult == 1 ? "1" : "2";
// 5. 构建实体
return new PlcProductionData
{
PlcIp = ip,
OccurTime = now,
LineCode = "line2",
WorkstationCode = workstationCode,
WorkstationName = "压装定位销&激光打标", // 补充工站名称
ProductModel = productModel,
ProductName = productName,
ProductCode = sn1,
SN1 = sn1,
Product1SN = sn1,
Product1Result = result.ToString(),
PinPressure1 = pressure.ToString(),
PinStroke1 = stroke.ToString(),
QualificationFlag = qualificationFlag,
ActualOutQty = actualOutput.ToString(),
QualifiedQty = qualifiedQty.ToString(),
FailedQty = failedQty.ToString(),
ProductionCycle = (int)Math.Round(cycleTime),
CreatedBy = "PLC_System",
CreatedTime = now,
};
}
catch (Exception ex)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] OP058读取异常{ex.Message}");
return null;
}
}
/// <summary>
/// 读取OP060数据高低压接头拧紧工位DB1001
/// </summary>
public async Task<PlcProductionData> ReadOP060DataAsync(Plc plc, string ip, string workstationCode)
{
// 前置校验:快速失败
if (plc == null || !plc.IsConnected) return null;
if (string.IsNullOrWhiteSpace(ip) || string.IsNullOrWhiteSpace(workstationCode))
throw new ArgumentNullException("IP或工位编码不能为空");
try
{
// 1. 批量创建并行读取任务
var stringTasks = new Dictionary<string, Task<string>>
{
{ "产品型号", ReadPlcStringAsync(plc, _op060StringMap["产品型号"].Addr, _op060StringMap["产品型号"].Len) },
{ "产品名称", ReadPlcStringAsync(plc, _op060StringMap["产品名称"].Addr, _op060StringMap["产品名称"].Len) },
{ "SN_1", ReadPlcStringAsync(plc, _op060StringMap["SN_1"].Addr, _op060StringMap["SN_1"].Len) },
{ "SN_2", ReadPlcStringAsync(plc, _op060StringMap["SN_2"].Addr, _op060StringMap["SN_2"].Len) }
};
var intTasks = new Dictionary<string, Task<int>>
{
{ "运行状态", ReadPlcIntAsync(plc, _op060IntMap["运行状态"]) },
{ "设备模式", ReadPlcIntAsync(plc, _op060IntMap["设备模式"]) },
{ "设备在线状态", ReadPlcIntAsync(plc, _op060IntMap["设备在线状态"]) },
{ "生产模式", ReadPlcIntAsync(plc, _op060IntMap["生产模式"]) },
{ "实际产量", ReadPlcIntAsync(plc, _op060IntMap["实际产量"]) },
{ "合格数量", ReadPlcIntAsync(plc, _op060IntMap["合格数量"]) },
{ "失败数量", ReadPlcIntAsync(plc, _op060IntMap["失败数量"]) },
{ "产品总结果", ReadPlcIntAsync(plc, _op060IntMap["产品总结果"]) },
{ "1#螺丝结果", ReadPlcIntAsync(plc, _op060IntMap["1#螺丝结果"]) },
{ "2#螺丝结果", ReadPlcIntAsync(plc, _op060IntMap["2#螺丝结果"]) },
{ "3#螺丝结果", ReadPlcIntAsync(plc, _op060IntMap["3#螺丝结果"]) },
{ "4#螺丝结果", ReadPlcIntAsync(plc, _op060IntMap["4#螺丝结果"]) }
};
var realTasks = new Dictionary<string, Task<float>>
{
{ "1#螺丝扭矩", ReadPlcRealAsync(plc, _op060IntMap["1#螺丝扭矩"]) },
{ "1#螺丝深度", ReadPlcRealAsync(plc, _op060IntMap["1#螺丝深度"]) },
{ "1#螺丝角度", ReadPlcRealAsync(plc, _op060IntMap["1#螺丝角度"]) },
{ "2#螺丝扭矩", ReadPlcRealAsync(plc, _op060IntMap["2#螺丝扭矩"]) },
{ "2#螺丝深度", ReadPlcRealAsync(plc, _op060IntMap["2#螺丝深度"]) },
{ "2#螺丝角度", ReadPlcRealAsync(plc, _op060IntMap["2#螺丝角度"]) },
{ "3#螺丝扭矩", ReadPlcRealAsync(plc, _op060IntMap["3#螺丝扭矩"]) },
{ "3#螺丝深度", ReadPlcRealAsync(plc, _op060IntMap["3#螺丝深度"]) },
{ "3#螺丝角度", ReadPlcRealAsync(plc, _op060IntMap["3#螺丝角度"]) },
{ "4#螺丝扭矩", ReadPlcRealAsync(plc, _op060IntMap["4#螺丝扭矩"]) },
{ "4#螺丝深度", ReadPlcRealAsync(plc, _op060IntMap["4#螺丝深度"]) },
{ "4#螺丝角度", ReadPlcRealAsync(plc, _op060IntMap["4#螺丝角度"]) },
{ "节拍时间", ReadPlcRealAsync(plc, _op060IntMap["节拍时间"]) }
};
// 2. 并行等待所有任务完成
var allTasks = new List<Task>();
allTasks.AddRange(stringTasks.Values);
allTasks.AddRange(intTasks.Values);
allTasks.AddRange(realTasks.Values);
await Task.WhenAll(allTasks).ConfigureAwait(false);
// 3. 提取结果
var now = DateTime.Now;
var productModel = stringTasks["产品型号"].Result ?? string.Empty;
var productName = stringTasks["产品名称"].Result ?? string.Empty;
var sn1 = stringTasks["SN_1"].Result ?? string.Empty;
var sn2 = stringTasks["SN_2"].Result ?? string.Empty;
var runStatus = intTasks["运行状态"].Result;
var machineModel = intTasks["设备模式"].Result;
var onlineStatus = intTasks["设备在线状态"].Result;
var produceModel = intTasks["生产模式"].Result;
var actualOutput = intTasks["实际产量"].Result;
var qualifiedQty = intTasks["合格数量"].Result;
var failedQty = intTasks["失败数量"].Result;
var productTotalResult = intTasks["产品总结果"].Result;
var screw1Result = intTasks["1#螺丝结果"].Result;
var screw2Result = intTasks["2#螺丝结果"].Result;
var screw3Result = intTasks["3#螺丝结果"].Result;
var screw4Result = intTasks["4#螺丝结果"].Result;
var screw1Torque = realTasks["1#螺丝扭矩"].Result;
var screw1Depth = realTasks["1#螺丝深度"].Result;
var screw1Angle = realTasks["1#螺丝角度"].Result;
var screw2Torque = realTasks["2#螺丝扭矩"].Result;
var screw2Depth = realTasks["2#螺丝深度"].Result;
var screw2Angle = realTasks["2#螺丝角度"].Result;
var screw3Torque = realTasks["3#螺丝扭矩"].Result;
var screw3Depth = realTasks["3#螺丝深度"].Result;
var screw3Angle = realTasks["3#螺丝角度"].Result;
var screw4Torque = realTasks["4#螺丝扭矩"].Result;
var screw4Depth = realTasks["4#螺丝深度"].Result;
var screw4Angle = realTasks["4#螺丝角度"].Result;
var cycleTime = realTasks["节拍时间"].Result;
// 4. 业务逻辑转换
var reworkFlag = produceModel == 2 ? "1" : "0";
var produceModelDesc = produceModel switch
{
1 => "点检模式",
2 => "返工模式",
4 => "样件模式",
5 => "正常模式",
_ => produceModel.ToString()
};
var onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线";
var qualificationFlag = productTotalResult == 1 ? "1" : "2";
// 6. 构建实体
// 6. 构建完整实体(覆盖所有螺丝参数字段)
return new PlcProductionData
{
// 基础字段
PlcIp = ip,
OccurTime = now,
LineCode = "line2",
WorkstationCode = workstationCode,
WorkstationName = "高低压接头拧紧工位", // 补充工站名称
ProductModel = productModel,
ProductName = productName,
ProductCode = sn1,
SN1 = sn1,
SN2 = sn2,
ReworkFlag = reworkFlag,
Automanual = machineModel,
Runstatus = runStatus,
OnlineStatus = onlineStatusDesc,
ProduceModel = produceModelDesc,
QualificationFlag = qualificationFlag,
ActualOutQty = actualOutput.ToString(),
QualifiedQty = qualifiedQty.ToString(),
FailedQty = failedQty.ToString(),
ProductionCycle = (int)Math.Round(cycleTime),
CreatedBy = "PLC",
CreatedTime = now,
// 螺丝1参数完整赋值
Screw1Result = screw1Result.ToString(),
Screw1Torque = screw1Torque.ToString("F2"),
Screw1Depth = screw1Depth.ToString("F2"),
Screw1Angle = screw1Angle.ToString("F2"),
Screw1TightenTime = realTasks["1#螺丝时间"].Result.ToString("F2"),
// 螺丝2参数完整赋值
Screw2Result = screw2Result.ToString(),
Screw2Torque = screw2Torque.ToString("F2"),
Screw2Depth = screw2Depth.ToString("F2"),
Screw2Angle = screw2Angle.ToString("F2"),
Screw2TightenTime = realTasks["2#螺丝时间"].Result.ToString("F2"),
// 螺丝3参数完整赋值
Screw3Result = screw3Result.ToString(),
Screw3Torque = screw3Torque.ToString("F2"),
Screw3Depth = screw3Depth.ToString("F2"),
Screw3Angle = screw3Angle.ToString("F2"),
Screw3TightenTime = realTasks["3#螺丝时间"].Result.ToString("F2"),
// 螺丝4参数完整赋值
Screw4Result = screw4Result.ToString(),
Screw4Torque = screw4Torque.ToString("F2"),
Screw4Depth = screw4Depth.ToString("F2"),
Screw4Angle = screw4Angle.ToString("F2"),
Screw4TightenTime = realTasks["4#螺丝时间"].Result.ToString("F2"),
};
}
catch (Exception ex)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] OP060读取异常{ex.Message}");
return null;
}
}
/// <summary>
/// OP070-1数据读取 - 效率优化版
/// </summary>
private async Task<PlcProductionData?> ReadOP070_1DataAsync(Plc plc, string ip, string workstationCode)
{
// 前置核心校验避免无效PLC操作节省10+ms无效耗时
if (plc == null || !plc.IsConnected)
{
Console.WriteLine($"OP070-1({ip})PLC连接无效跳过数据读取");
// 若业务允许,可返回空实体而非抛异常,根据实际场景调整
return new PlcProductionData { PlcIp = ip, WorkstationCode = workstationCode };
}
try
{
// 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["站位结果"]);
// DInt任务单独提取避免字典开销
var taskActualOutput = ReadPlcIntAsync(plc, _op050IntMap["实际产量"]);
var taskQualifiedQty = ReadPlcIntAsync(plc, _op050IntMap["合格数量"]);
var taskFailedQty = ReadPlcIntAsync(plc, _op050IntMap["失败数量"]);
// ========== Real字段并行任务 ==========
var taskCycleTime = ReadPlcRealAsync(plc, _op070_1IntMap["节拍时间"]);
// 2. 等待所有并行任务完成(核心:耗时=最慢的单个读取任务,而非总和)
await Task.WhenAll(
// 字符串任务
taskProductName, taskOrderName, taskProductModel, taskSN1, taskSN2,
// Int任务
taskRunStatus, taskMachineModel, taskOnlineStatus, taskByPass, taskProduceModel,
taskTrayNo, taskCameraResult, taskStationResult,
// Real任务
taskCycleTime,
// DInt任务
taskActualOutput, taskQualifiedQty, taskFailedQty);
// 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 trayNo = await taskTrayNo;
int cameraResult = await taskCameraResult;
int stationResult = await taskStationResult;
int actualOutput = await taskActualOutput;
int qualifiedQty = await taskQualifiedQty;
int failedQty = await taskFailedQty;
// 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",
WorkstationName = "点散热胶",
WorkstationCode = workstationCode,
ProductModel = productModel,
ProductName = productName,
ProductCode = sn2,
SN1 = sn1,
SN2 = sn2,
QualificationFlag = qualificationFlag,
ActualOutQty = actualOutput.ToString(),
QualifiedQty = qualifiedQty.ToString(),
FailedQty = failedQty.ToString(),
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;
}
}
/// <summary>
/// OP075数据读取
/// </summary>
private async Task<PlcProductionData?> ReadOP075DataAsync(Plc plc, string ip, string workstationCode)
{
// 前置核心校验避免无效PLC操作节省10+ms无效耗时
if (plc == null || !plc.IsConnected)
{
Console.WriteLine($"OP075({ip})PLC连接无效跳过数据读取");
// 返回基础实体避免业务空引用可根据实际场景调整为return null
return new PlcProductionData { PlcIp = ip, WorkstationCode = workstationCode };
}
try
{
// 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 taskTrayNo = ReadPlcIntAsync(plc, _op075IntMap["托盘号"]);
var taskStationResult = ReadPlcIntAsync(plc, _op075IntMap["站位结果"]);
// ========== Real字段并行任务 ==========
var taskCycleTime = ReadPlcRealAsync(plc, _op075IntMap["节拍时间"]);
// DInt任务单独提取避免字典开销
var taskActualOutput = ReadPlcIntAsync(plc, _op050IntMap["实际产量"]);
var taskQualifiedQty = ReadPlcIntAsync(plc, _op050IntMap["合格数量"]);
var taskFailedQty = ReadPlcIntAsync(plc, _op050IntMap["失败数量"]);
// 2. 等待所有并行任务完成(核心:耗时=最慢的单个读取任务,而非总和)
await Task.WhenAll(
// 字符串任务
taskProductName, taskOrderName, taskProductModel, taskSN1, taskSN2, taskChipSN,
// Int任务
taskRunStatus, taskMachineModel, taskOnlineStatus, taskByPass, taskProduceModel,
taskTrayNo, taskStationResult,
// Real任务
taskCycleTime
// DInt任务
, taskActualOutput, taskQualifiedQty, taskFailedQty
);
// 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 trayNo = await taskTrayNo;
int stationResult = await taskStationResult;
int actualOutput = await taskActualOutput;
int qualifiedQty = await taskQualifiedQty;
int failedQty = await taskFailedQty;
// 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,
WorkstationName = "PWM折弯&装配",
ProductModel = productModel,
ProductName = productName,
ProductCode = sn2,
SN1 = sn1,
SN2 = sn2,
ChipSN = chipsn, // 保留芯片SN独有字段
QualificationFlag = qualificationFlag,
ActualOutQty = actualOutput.ToString(),
QualifiedQty = qualifiedQty.ToString(),
FailedQty = failedQty.ToString(),
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}");
// 异常时返回基础实体,避免业务空引用
return null;
}
}
/// <summary>
/// 读取OP080-1数据 - 极致优化版(批量并行+内存复用+异步优化)
/// </summary>
/// <param name="plc">PLC实例</param>
/// <param name="ip">PLC IP</param>
/// <param name="workstationCode">工位编码</param>
/// <param name="strSaveRequest">保存请求类型</param>
/// <returns>PLC生产数据</returns>
private async Task<PlcProductionData?> ReadOP080_1DataAsync(Plc plc, string ip, string workstationCode, string strSaveRequest)
{
// 前置核心校验避免无效PLC操作节省10+ms无效耗时
if (plc == null || !plc.IsConnected)
{
return null;
}
try
{
// ========== 阶段1批量创建并行任务按类型分组减少分散管理 ==========
// 1.1 字符串字段任务6个- 批量存储
var stringTasks = new List<Task<string>>
{
ReadPlcStringAsync(plc, _op080_1StringMap["订单名称"].Addr, _op080_1StringMap["订单名称"].Len),
ReadPlcStringAsync(plc, _op080_1StringMap["产品名称"].Addr, _op080_1StringMap["产品名称"].Len),
ReadPlcStringAsync(plc, _op080_1StringMap["合装位机壳_SN"].Addr, _op080_1StringMap["合装位机壳_SN"].Len),
ReadPlcStringAsync(plc, _op080_1StringMap["合装位PCB_SN"].Addr, _op080_1StringMap["合装位PCB_SN"].Len),
ReadPlcStringAsync(plc, _op080_1StringMap["拧紧位机壳_SN"].Addr, _op080_1StringMap["拧紧位机壳_SN"].Len),
ReadPlcStringAsync(plc, _op080_1StringMap["拧紧位PCB_SN"].Addr, _op080_1StringMap["拧紧位PCB_SN"].Len)
};
// 1.2 Int字段任务17个- 批量存储
var intTasks = new List<Task<int>>
{
// 基础状态字段
ReadPlcIntAsync(plc, _op080_1IntMap["运行状态"]),
ReadPlcIntAsync(plc, _op080_1IntMap["设备模式"]),
ReadPlcIntAsync(plc, _op080_1IntMap["设备在线状态"]),
ReadPlcIntAsync(plc, _op080_1IntMap["ByPass"]),
ReadPlcIntAsync(plc, _op080_1IntMap["生产模式"]),
// 请求/托盘字段
ReadPlcIntAsync(plc, _op080_1IntMap["合装工位查询请求"]),
ReadPlcIntAsync(plc, _op080_1IntMap["合装结果保存请求"]),
ReadPlcIntAsync(plc, _op080_1IntMap["拧紧结果保存请求"]),
ReadPlcIntAsync(plc, _op080_1IntMap["合装位托盘号"]),
ReadPlcIntAsync(plc, _op080_1IntMap["拧紧位托盘号"]),
// 螺钉结果字段7个
ReadPlcIntAsync(plc, _op080_1IntMap["1号螺钉_结果"]),
ReadPlcIntAsync(plc, _op080_1IntMap["2号螺钉_结果"]),
ReadPlcIntAsync(plc, _op080_1IntMap["3号螺钉_结果"]),
ReadPlcIntAsync(plc, _op080_1IntMap["4号螺钉_结果"]),
ReadPlcIntAsync(plc, _op080_1IntMap["5号螺钉_结果"]),
ReadPlcIntAsync(plc, _op080_1IntMap["6号螺钉_结果"]),
ReadPlcIntAsync(plc, _op080_1IntMap["7号螺钉_结果"])
};
// DInt双整数读取任务复用ReadPlcIntAsyncPLC底层兼容DInt转int
var dIntReadTasks = new Dictionary<string, Task<int>>
{
{ "实际产量", ReadPlcIntAsync(plc, _op080_1IntMap["实际产量"]) },
{ "合格数量", ReadPlcIntAsync(plc, _op080_1IntMap["合格数量"]) },
{ "失败数量", ReadPlcIntAsync(plc, _op080_1IntMap["失败数量"]) }
};
// 1.3 Real字段任务28个- 按螺钉分组,批量存储(减少硬编码)
var realTasks = new List<Task<float>>();
// 预定义螺钉字段前缀复用数组减少GC
var screwPrefixes = new[] { "1号螺钉_", "2号螺钉_", "3号螺钉_", "4号螺钉_", "5号螺钉_", "6号螺钉_", "7号螺钉_" };
var screwDimensions = new[] { "扭矩", "深度", "角度", "拧紧时间" };
foreach (var prefix in screwPrefixes)
{
foreach (var dim in screwDimensions)
{
realTasks.Add(ReadPlcRealAsync(plc, _op080_1IntMap[$"{prefix}{dim}"]));
}
}
// ========== 阶段2批量等待任务完成核心优化异步上下文取消 ==========
var allTasks = new List<Task>();
allTasks.AddRange(stringTasks); // 字符串任务Task<string> 继承自 Task
allTasks.AddRange(intTasks); // Int任务Task<int> 继承自 Task
allTasks.AddRange(realTasks); // Real任务Task<float> 继承自 Task
allTasks.AddRange(dIntReadTasks.Values);
await Task.WhenAll(allTasks).ConfigureAwait(false); // 取消上下文捕获,提升性能
// ========== 阶段3批量获取结果索引访问减少临时变量 ==========
// 3.1 字符串结果(索引对应创建顺序)
string orderName = stringTasks[0].Result ?? string.Empty;
string productName = stringTasks[1].Result ?? string.Empty;
string hzMachineSN = stringTasks[2].Result ?? string.Empty;
string hzPcbsn = stringTasks[3].Result ?? string.Empty;
string njMachineSN = stringTasks[4].Result ?? string.Empty;
string njPcbsn = stringTasks[5].Result ?? string.Empty;
// 3.2 Int结果索引对应创建顺序
int runStatus = intTasks[0].Result;
int machineModel = intTasks[1].Result;
int onlineStatus = intTasks[2].Result;
int byPass = intTasks[3].Result;
int produceModel = intTasks[4].Result;
int hzQueryReq = intTasks[5].Result;
int hzSaveReq = intTasks[6].Result;
int njSaveReq = intTasks[7].Result;
int hzTrayNo = intTasks[8].Result;
int njTrayNo = intTasks[9].Result;
// 螺钉结果索引10-16
int[] screwResults = new[]
{
intTasks[10].Result, intTasks[11].Result, intTasks[12].Result,
intTasks[13].Result, intTasks[14].Result, intTasks[15].Result, intTasks[16].Result
};
int actualOutput = dIntReadTasks["实际产量"].Result;
int qualifiedQty = dIntReadTasks["合格数量"].Result;
int failedQty = dIntReadTasks["失败数量"].Result;
// 3.3 Real结果按螺钉维度批量读取索引0-277螺钉×4维度
float[] realResults = realTasks.Select(t => t.Result).ToArray();
// 按螺钉分组提取(复用数组,减少临时变量)
float[][] screwRealData = new float[7][];
for (int i = 0; i < 7; i++)
{
screwRealData[i] = realResults.Skip(i * 4).Take(4).ToArray();
}
// ========== 阶段4精简业务逻辑减少GC+CPU开销 ==========
// 4.1 状态描述复用静态字典减少switch开销
string produceModelDesc = produceModel switch
{
1 => "正常模式",
2 => "清线模式",
4 => "返工模式",
8 => "换型模式",
16 => "预热模式",
_ => $"未知({produceModel})"
};
string runStatusDesc = runStatus switch { 1 => "空闲", 2 => "运行中", 3 => "故障", _ => $"未知({runStatus})" };
string onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线";
// 4.2 合格/返工标志(无分支优化)
string reworkFlag = produceModel == 4 ? "1" : "0";
string qualificationFlag = screwResults.All(s => s == 1) ? "1" : "0";
// ========== 阶段5构建数据实体内存复用+精简赋值) ==========
var plcData = new PlcProductionData
{
// 基础字段(固定值直接赋值,无冗余操作)
PlcIp = ip,
OccurTime = DateTime.Now,
LineCode = "line2",
WorkstationCode = workstationCode,
WorkstationName = "PCBA组装&拧紧",
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,
ActualOutQty = actualOutput.ToString(),
QualifiedQty = qualifiedQty.ToString(),
FailedQty = failedQty.ToString(),
// 螺钉相关字段(批量赋值,减少重复代码)
// 1号螺钉
Screw1Result = screwResults[0].ToString(),
Screw1Torque = screwRealData[0][0].ToString("0.00"),
Screw1Depth = screwRealData[0][1].ToString("0.00"),
Screw1Angle = screwRealData[0][2].ToString("0.00"),
Screw1TightenTime = screwRealData[0][3].ToString("0.00"),
// 2号螺钉
Screw2Result = screwResults[1].ToString(),
Screw2Torque = screwRealData[1][0].ToString("0.00"),
Screw2Depth = screwRealData[1][1].ToString("0.00"),
Screw2Angle = screwRealData[1][2].ToString("0.00"),
Screw2TightenTime = screwRealData[1][3].ToString("0.00"),
// 3号螺钉
Screw3Result = screwResults[2].ToString(),
Screw3Torque = screwRealData[2][0].ToString("0.00"),
Screw3Depth = screwRealData[2][1].ToString("0.00"),
Screw3Angle = screwRealData[2][2].ToString("0.00"),
Screw3TightenTime = screwRealData[2][3].ToString("0.00"),
// 4号螺钉
Screw4Result = screwResults[3].ToString(),
Screw4Torque = screwRealData[3][0].ToString("0.00"),
Screw4Depth = screwRealData[3][1].ToString("0.00"),
Screw4Angle = screwRealData[3][2].ToString("0.00"),
Screw4TightenTime = screwRealData[3][3].ToString("0.00"),
// 5号螺钉
Screw5Result = screwResults[4].ToString(),
Screw5Torque = screwRealData[4][0].ToString("0.00"),
Screw5Depth = screwRealData[4][1].ToString("0.00"),
Screw5Angle = screwRealData[4][2].ToString("0.00"),
Screw5TightenTime = screwRealData[4][3].ToString("0.00"),
// 6号螺钉
Screw6Result = screwResults[5].ToString(),
Screw6Torque = screwRealData[5][0].ToString("0.00"),
Screw6Depth = screwRealData[5][1].ToString("0.00"),
Screw6Angle = screwRealData[5][2].ToString("0.00"),
Screw6TightenTime = screwRealData[5][3].ToString("0.00"),
// 7号螺钉
Screw7Result = screwResults[6].ToString(),
Screw7Torque = screwRealData[6][0].ToString("0.00"),
Screw7Depth = screwRealData[6][1].ToString("0.00"),
Screw7Angle = screwRealData[6][2].ToString("0.00"),
Screw7TightenTime = screwRealData[6][3].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,
CameraResult = string.Empty
};
return plcData;
}
catch (Exception ex)
{
// 增强异常日志包含IP+时间+堆栈)
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] OP080-1({ip})数据读取异常:{ex.Message}\n{ex.StackTrace}");
return null;
}
}
/// <summary>
/// 读取OP080-2 数据
/// </summary>
/// <param name="plc"></param>
/// <param name="ip"></param>
/// <param name="workstationCode"></param>
/// <returns></returns>
/// <summary>
private async Task<PlcProductionData?> 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-21=点检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作为工位编码
WorkstationName = "PCBA拧紧",
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;
}
}
/// <summary>
/// 读取OP080-3数据PWM压装&CUP上料&拧紧工位DB1001
/// </summary>
public async Task<PlcProductionData> ReadOP080_3DataAsync(Plc plc, string ip, string workstationCode)
{
// 前置校验:快速失败
if (plc == null || !plc.IsConnected) return null;
if (string.IsNullOrWhiteSpace(ip) || string.IsNullOrWhiteSpace(workstationCode))
throw new ArgumentNullException("IP或工位编码不能为空");
try
{
// 1. 批量创建并行读取任务
var stringTasks = new Dictionary<string, Task<string>>
{
{ "产品型号", ReadPlcStringAsync(plc, _op080_3StringMap["产品型号"].Addr, _op080_3StringMap["产品型号"].Len) },
{ "产品名称", ReadPlcStringAsync(plc, _op080_3StringMap["产品名称"].Addr, _op080_3StringMap["产品名称"].Len) },
{ "SN_1", ReadPlcStringAsync(plc, _op080_3StringMap["SN_1"].Addr, _op080_3StringMap["SN_1"].Len) },
{ "SN_2", ReadPlcStringAsync(plc, _op080_3StringMap["SN_2"].Addr, _op080_3StringMap["SN_2"].Len) }
};
var intTasks = new Dictionary<string, Task<int>>
{
{ "运行状态", ReadPlcIntAsync(plc, _op080_3IntMap["运行状态"]) },
{ "设备模式", ReadPlcIntAsync(plc, _op080_3IntMap["设备模式"]) },
{ "设备在线状态", ReadPlcIntAsync(plc, _op080_3IntMap["设备在线状态"]) },
{ "生产模式", ReadPlcIntAsync(plc, _op080_3IntMap["生产模式"]) },
{ "实际产量", ReadPlcIntAsync(plc, _op080_3IntMap["实际产量"]) },
{ "产品总结果", ReadPlcIntAsync(plc, _op080_3IntMap["产品总结果"]) },
{ "压机结果", ReadPlcIntAsync(plc, _op080_3IntMap["压机结果"]) },
{ "左螺丝枪结果", ReadPlcIntAsync(plc, _op080_3IntMap["左螺丝枪结果"]) },
{ "右螺丝枪结果", ReadPlcIntAsync(plc, _op080_3IntMap["右螺丝枪结果"]) },
{ "托盘号", ReadPlcIntAsync(plc, _op080_3IntMap["托盘号"]) }
};
var realTasks = new Dictionary<string, Task<float>>
{
{ "压机左压力值", ReadPlcRealAsync(plc, _op080_3IntMap["压机左压力值"]) },
{ "压机右压力值", ReadPlcRealAsync(plc, _op080_3IntMap["压机右压力值"]) },
{ "压机行程值", ReadPlcRealAsync(plc, _op080_3IntMap["压机行程值"]) },
{ "保压时间", ReadPlcRealAsync(plc, _op080_3IntMap["保压时间"]) },
{ "左螺丝枪扭矩", ReadPlcRealAsync(plc, _op080_3IntMap["左螺丝枪扭矩"]) },
{ "左螺丝枪角度", ReadPlcRealAsync(plc, _op080_3IntMap["左螺丝枪角度"]) },
{ "左螺丝枪深度", ReadPlcRealAsync(plc, _op080_3IntMap["左螺丝枪深度"]) },
{ "左螺丝枪时间", ReadPlcRealAsync(plc, _op080_3IntMap["左螺丝枪时间"]) },
{ "右螺丝枪扭矩", ReadPlcRealAsync(plc, _op080_3IntMap["右螺丝枪扭矩"]) },
{ "右螺丝枪角度", ReadPlcRealAsync(plc, _op080_3IntMap["右螺丝枪角度"]) },
{ "右螺丝枪深度", ReadPlcRealAsync(plc, _op080_3IntMap["右螺丝枪深度"]) },
{ "右螺丝枪时间", ReadPlcRealAsync(plc, _op080_3IntMap["右螺丝枪时间"]) },
{ "节拍时间", ReadPlcRealAsync(plc, _op080_3IntMap["节拍时间"]) }
};
// 2. 并行等待所有任务完成
var allTasks = new List<Task>();
allTasks.AddRange(stringTasks.Values);
allTasks.AddRange(intTasks.Values);
allTasks.AddRange(realTasks.Values);
await Task.WhenAll(allTasks).ConfigureAwait(false);
// 3. 提取结果
var now = DateTime.Now;
var productModel = stringTasks["产品型号"].Result ?? string.Empty;
var productName = stringTasks["产品名称"].Result ?? string.Empty;
var sn1 = stringTasks["SN_1"].Result ?? string.Empty;
var sn2 = stringTasks["SN_2"].Result ?? string.Empty;
var runStatus = intTasks["运行状态"].Result;
var machineModel = intTasks["设备模式"].Result;
var onlineStatus = intTasks["设备在线状态"].Result;
var produceModel = intTasks["生产模式"].Result;
var actualOutput = intTasks["实际产量"].Result;
var productTotalResult = intTasks["产品总结果"].Result;
var pressResult = intTasks["压机结果"].Result;
var leftScrewResult = intTasks["左螺丝枪结果"].Result;
var rightScrewResult = intTasks["右螺丝枪结果"].Result;
var trayNo = intTasks["托盘号"].Result.ToString();
var pressLeftPressure = realTasks["压机左压力值"].Result;
var pressRightPressure = realTasks["压机右压力值"].Result;
var pressStroke = realTasks["压机行程值"].Result;
var pressHoldTime = realTasks["保压时间"].Result;
var leftScrewTorque = realTasks["左螺丝枪扭矩"].Result;
var leftScrewAngle = realTasks["左螺丝枪角度"].Result;
var leftScrewDepth = realTasks["左螺丝枪深度"].Result;
var leftScrewTime = realTasks["左螺丝枪时间"].Result;
var rightScrewTorque = realTasks["右螺丝枪扭矩"].Result;
var rightScrewAngle = realTasks["右螺丝枪角度"].Result;
var rightScrewDepth = realTasks["右螺丝枪深度"].Result;
var rightScrewTime = realTasks["右螺丝枪时间"].Result;
var cycleTime = realTasks["节拍时间"].Result;
// 4. 业务逻辑转换
var reworkFlag = produceModel == 2 ? "1" : "0";
var produceModelDesc = produceModel switch
{
1 => "点检模式",
2 => "返工模式",
4 => "样件模式",
5 => "正常模式",
_ => produceModel.ToString()
};
var onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线";
var qualificationFlag = productTotalResult == 1 ? "1" : "2";
// 6. 构建完整实体(覆盖所有工艺参数字段)
return new PlcProductionData
{
// 基础字段
PlcIp = ip,
OccurTime = now,
LineCode = "line2",
WorkstationCode = workstationCode,
WorkstationName = "PWM压装&CUP上料&拧紧工位",
ProductModel = productModel,
ProductName = productName,
ProductCode = sn1,
SN1 = sn1,
SN2 = sn2,
TrayNo = trayNo,
ReworkFlag = reworkFlag,
Automanual = machineModel,
Runstatus = runStatus,
OnlineStatus = onlineStatusDesc,
ProduceModel = produceModelDesc,
QualificationFlag = qualificationFlag,
ProductionCycle = (int)Math.Round(cycleTime),
CreatedBy = "PLC",
CreatedTime = now,
// 压机参数
PinPressure1 = pressLeftPressure.ToString("F2"),//压机左压力值
PinPressure2 = pressRightPressure.ToString("F2"),//压机右压力值
PinStroke1 = pressStroke.ToString("F2"),//压机行程值
PressHoldTime = pressHoldTime.ToString(),//保压时间
// 左螺丝枪参数
Screw1Result = leftScrewResult.ToString(),
Screw1Torque = leftScrewTorque.ToString("F2"),
Screw1Depth = leftScrewDepth.ToString("F2"),
Screw1Angle = leftScrewAngle.ToString("F2"),
Screw1TightenTime = leftScrewTime.ToString("F2"),
// 右螺丝枪参数
Screw2Result = rightScrewResult.ToString(),
Screw2Torque = rightScrewTorque.ToString("F2"),
Screw2Depth = rightScrewDepth.ToString("F2"),
Screw2Angle = rightScrewAngle.ToString("F2"),
Screw2TightenTime = rightScrewTime.ToString("F2"),
};
}
catch (Exception ex)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] OP080-3读取异常{ex.Message}");
return null;
}
}
/// <summary>
/// 读取OP085数据自动上料到波峰焊工位DB1001
/// </summary>
public async Task<PlcProductionData> ReadOP085DataAsync(Plc plc, string ip, string workstationCode)
{
// 前置校验:快速失败
if (plc == null || !plc.IsConnected) return null;
if (string.IsNullOrWhiteSpace(ip) || string.IsNullOrWhiteSpace(workstationCode))
throw new ArgumentNullException("IP或工位编码不能为空");
try
{
// 1. 批量创建并行读取任务
var stringTasks = new Dictionary<string, Task<string>>
{
{ "产品型号", ReadPlcStringAsync(plc, _op085StringMap["产品型号"].Addr, _op085StringMap["产品型号"].Len) },
{ "产品名称", ReadPlcStringAsync(plc, _op085StringMap["产品名称"].Addr, _op085StringMap["产品名称"].Len) },
{ "波峰焊托盘条码", ReadPlcStringAsync(plc, _op085StringMap["波峰焊托盘条码"].Addr, _op085StringMap["波峰焊托盘条码"].Len) },
{ "穴位1产品SN", ReadPlcStringAsync(plc, _op085StringMap["穴位1产品SN"].Addr, _op085StringMap["穴位1产品SN"].Len) },
{ "穴位2产品SN", ReadPlcStringAsync(plc, _op085StringMap["穴位2产品SN"].Addr, _op085StringMap["穴位2产品SN"].Len) },
{ "穴位3产品SN", ReadPlcStringAsync(plc, _op085StringMap["穴位3产品SN"].Addr, _op085StringMap["穴位3产品SN"].Len) },
{ "穴位4产品SN", ReadPlcStringAsync(plc, _op085StringMap["穴位4产品SN"].Addr, _op085StringMap["穴位4产品SN"].Len) }
};
var intTasks = new Dictionary<string, Task<int>>
{
{ "运行状态", ReadPlcIntAsync(plc, _op085IntMap["运行状态"]) },
{ "设备模式", ReadPlcIntAsync(plc, _op085IntMap["设备模式"]) },
{ "设备在线状态", ReadPlcIntAsync(plc, _op085IntMap["设备在线状态"]) },
{ "生产模式", ReadPlcIntAsync(plc, _op085IntMap["生产模式"]) },
{ "实际产量", ReadPlcIntAsync(plc, _op085IntMap["实际产量"]) },
{ "线体托盘号", ReadPlcIntAsync(plc, _op085IntMap["线体托盘号"]) }
};
var realTasks = new Dictionary<string, Task<float>>
{
{ "节拍时间", ReadPlcRealAsync(plc, _op085IntMap["节拍时间"]) }
};
// 2. 并行等待所有任务完成
var allTasks = new List<Task>();
allTasks.AddRange(stringTasks.Values);
allTasks.AddRange(intTasks.Values);
allTasks.AddRange(realTasks.Values);
await Task.WhenAll(allTasks).ConfigureAwait(false);
// 3. 提取结果
var now = DateTime.Now;
var productModel = stringTasks["产品型号"].Result ?? string.Empty;
var productName = stringTasks["产品名称"].Result ?? string.Empty;
var trayBarcode = stringTasks["波峰焊托盘条码"].Result ?? string.Empty;
var sn1 = stringTasks["穴位1产品SN"].Result ?? string.Empty;
var sn2 = stringTasks["穴位2产品SN"].Result ?? string.Empty;
var sn3 = stringTasks["穴位3产品SN"].Result ?? string.Empty;
var sn4 = stringTasks["穴位4产品SN"].Result ?? string.Empty;
var runStatus = intTasks["运行状态"].Result;
var machineModel = intTasks["设备模式"].Result;
var onlineStatus = intTasks["设备在线状态"].Result;
var produceModel = intTasks["生产模式"].Result;
var actualOutput = intTasks["实际产量"].Result;
var lineTrayNo = intTasks["线体托盘号"].Result.ToString();
var cycleTime = realTasks["节拍时间"].Result;
// 4. 业务逻辑转换
var reworkFlag = produceModel == 2 ? "1" : "0";
var produceModelDesc = produceModel switch
{
1 => "点检模式",
2 => "返工模式",
4 => "样件模式",
5 => "正常模式",
_ => produceModel.ToString()
};
var onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线";
var qualificationFlag = "1"; // 上料工位默认合格
// 5. 构建完整实体
return new PlcProductionData
{
// 基础字段
PlcIp = ip,
OccurTime = now,
LineCode = "line2",
WorkstationCode = workstationCode,
WorkstationName = "自动上料到波峰焊工位",
ProductModel = productModel,
ProductName = productName,
ProductCode = sn1,
SN1 = sn1,
SN2 = sn2,
Product1SN = sn1,
Product2SN = sn2,
Product3SN = sn3,
Product4SN = sn4,
TrayNo = lineTrayNo,
TrayBarcode = trayBarcode,
ReworkFlag = reworkFlag,
Automanual = machineModel,
Runstatus = runStatus,
OnlineStatus = onlineStatusDesc,
ProduceModel = produceModelDesc,
QualificationFlag = qualificationFlag,
ProductionCycle = (int)Math.Round(cycleTime),
CreatedBy = "PLC",
CreatedTime = now,
};
}
catch (Exception ex)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] OP085读取异常{ex.Message}");
return null;
}
}
/// <summary>
/// 读取OP100数据手动上料壳体&盖板工位DB1001
/// </summary>
public async Task<PlcProductionData> ReadOP100DataAsync(Plc plc, string ip, string workstationCode)
{
// 前置校验:快速失败
if (plc == null || !plc.IsConnected) return null;
if (string.IsNullOrWhiteSpace(ip) || string.IsNullOrWhiteSpace(workstationCode))
throw new ArgumentNullException("IP或工位编码不能为空");
try
{
// 1. 批量创建并行读取任务
var stringTasks = new Dictionary<string, Task<string>>
{
{ "产品型号", ReadPlcStringAsync(plc, _op100StringMap["产品型号"].Addr, _op100StringMap["产品型号"].Len) },
{ "产品名称", ReadPlcStringAsync(plc, _op100StringMap["产品名称"].Addr, _op100StringMap["产品名称"].Len) },
{ "产品SN", ReadPlcStringAsync(plc, _op100StringMap["产品SN"].Addr, _op100StringMap["产品SN"].Len) }
};
var intTasks = new Dictionary<string, Task<int>>
{
{ "运行状态", ReadPlcIntAsync(plc, _op100IntMap["运行状态"]) },
{ "设备模式", ReadPlcIntAsync(plc, _op100IntMap["设备模式"]) },
{ "设备在线状态", ReadPlcIntAsync(plc, _op100IntMap["设备在线状态"]) },
{ "生产模式", ReadPlcIntAsync(plc, _op100IntMap["生产模式"]) },
{ "实际产量", ReadPlcIntAsync(plc, _op100IntMap["实际产量"]) },
{ "托盘号", ReadPlcIntAsync(plc, _op100IntMap["托盘号"]) }
};
var realTasks = new Dictionary<string, Task<float>>
{
{ "节拍时间", ReadPlcRealAsync(plc, _op100IntMap["节拍时间"]) }
};
// 2. 并行等待所有任务完成
var allTasks = new List<Task>();
allTasks.AddRange(stringTasks.Values);
allTasks.AddRange(intTasks.Values);
allTasks.AddRange(realTasks.Values);
await Task.WhenAll(allTasks).ConfigureAwait(false);
// 3. 提取结果
var now = DateTime.Now;
var productModel = stringTasks["产品型号"].Result ?? string.Empty;
var productName = stringTasks["产品名称"].Result ?? string.Empty;
var sn1 = stringTasks["产品SN"].Result ?? string.Empty;
var runStatus = intTasks["运行状态"].Result;
var machineModel = intTasks["设备模式"].Result;
var onlineStatus = intTasks["设备在线状态"].Result;
var produceModel = intTasks["生产模式"].Result;
var actualOutput = intTasks["实际产量"].Result;
var trayNo = intTasks["托盘号"].Result.ToString();
var cycleTime = realTasks["节拍时间"].Result;
// 4. 业务逻辑转换
var reworkFlag = produceModel == 2 ? "1" : "0";
var produceModelDesc = produceModel switch
{
1 => "点检模式",
2 => "返工模式",
4 => "样件模式",
5 => "正常模式",
_ => produceModel.ToString()
};
var onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线";
var qualificationFlag = "1"; // 手动上料工位默认合格
// 6. 构建完整实体
return new PlcProductionData
{
// 基础字段
PlcIp = ip,
OccurTime = now,
LineCode = "line2",
WorkstationCode = workstationCode,
WorkstationName = "手动上料壳体&盖板工位",
ProductModel = productModel,
ProductName = productName,
ProductCode = sn1,
SN1 = sn1,
TrayNo = trayNo,
ReworkFlag = reworkFlag,
Automanual = machineModel,
Runstatus = runStatus,
OnlineStatus = onlineStatusDesc,
ProduceModel = produceModelDesc,
QualificationFlag = qualificationFlag,
ProductionCycle = (int)Math.Round(cycleTime),
CreatedBy = "PLC_System",
CreatedTime = now,
};
}
catch (Exception ex)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] OP100读取异常{ex.Message}");
return null;
}
}
/// <summary>
/// 读取OP1011数据HV连接器装配工位DB1001
/// </summary>
public async Task<PlcProductionData> ReadOP1011DataAsync(Plc plc, string ip, string workstationCode)
{
// 前置校验:快速失败
if (plc == null || !plc.IsConnected) return null;
if (string.IsNullOrWhiteSpace(ip) || string.IsNullOrWhiteSpace(workstationCode))
throw new ArgumentNullException("IP或工位编码不能为空");
try
{
// 1. 批量创建并行读取任务
var stringTasks = new Dictionary<string, Task<string>>
{
{ "产品型号", ReadPlcStringAsync(plc, _op1011StringMap["产品型号"].Addr, _op1011StringMap["产品型号"].Len) },
{ "产品名称", ReadPlcStringAsync(plc, _op1011StringMap["产品名称"].Addr, _op1011StringMap["产品名称"].Len) },
{ "查询SN", ReadPlcStringAsync(plc, _op1011StringMap["查询SN"].Addr, _op1011StringMap["查询SN"].Len) },
{ "上传结果SN", ReadPlcStringAsync(plc, _op1011StringMap["上传结果SN"].Addr, _op1011StringMap["上传结果SN"].Len) }
};
var intTasks = new Dictionary<string, Task<int>>
{
{ "运行状态", ReadPlcIntAsync(plc, _op1011IntMap["运行状态"]) },
{ "设备模式", ReadPlcIntAsync(plc, _op1011IntMap["设备模式"]) },
{ "设备在线状态", ReadPlcIntAsync(plc, _op1011IntMap["设备在线状态"]) },
{ "生产模式", ReadPlcIntAsync(plc, _op1011IntMap["生产模式"]) },
{ "螺钉枪程序号", ReadPlcIntAsync(plc, _op1011IntMap["螺钉枪程序号"]) },
{ "实际产量", ReadPlcIntAsync(plc, _op1011IntMap["实际产量"]) },
{ "产品总结果", ReadPlcIntAsync(plc, _op1011IntMap["产品总结果"]) },
{ "1#结果", ReadPlcIntAsync(plc, _op1011IntMap["1#结果"]) },
{ "2#结果", ReadPlcIntAsync(plc, _op1011IntMap["2#结果"]) },
{ "3#结果", ReadPlcIntAsync(plc, _op1011IntMap["3#结果"]) },
{ "4#结果", ReadPlcIntAsync(plc, _op1011IntMap["4#结果"]) }
};
var realTasks = new Dictionary<string, Task<float>>
{
{ "1#扭矩", ReadPlcRealAsync(plc, _op1011IntMap["1#扭矩"]) },
{ "2#扭矩", ReadPlcRealAsync(plc, _op1011IntMap["2#扭矩"]) },
{ "3#扭矩", ReadPlcRealAsync(plc, _op1011IntMap["3#扭矩"]) },
{ "4#扭矩", ReadPlcRealAsync(plc, _op1011IntMap["4#扭矩"]) },
{ "1#转角", ReadPlcRealAsync(plc, _op1011IntMap["1#转角"]) },
{ "2#转角", ReadPlcRealAsync(plc, _op1011IntMap["2#转角"]) },
{ "3#转角", ReadPlcRealAsync(plc, _op1011IntMap["3#转角"]) },
{ "4#转角", ReadPlcRealAsync(plc, _op1011IntMap["4#转角"]) },
{ "1#深度", ReadPlcRealAsync(plc, _op1011IntMap["1#深度"]) },
{ "2#深度", ReadPlcRealAsync(plc, _op1011IntMap["2#深度"]) },
{ "3#深度", ReadPlcRealAsync(plc, _op1011IntMap["3#深度"]) },
{ "4#深度", ReadPlcRealAsync(plc, _op1011IntMap["4#深度"]) },
{ "节拍时间", ReadPlcRealAsync(plc, _op1011IntMap["节拍时间"]) }
};
// 2. 并行等待所有任务完成
var allTasks = new List<Task>();
allTasks.AddRange(stringTasks.Values);
allTasks.AddRange(intTasks.Values);
allTasks.AddRange(realTasks.Values);
await Task.WhenAll(allTasks).ConfigureAwait(false);
// 3. 提取结果
var now = DateTime.Now;
var productModel = stringTasks["产品型号"].Result ?? string.Empty;
var productName = stringTasks["产品名称"].Result ?? string.Empty;
var sn1 = stringTasks["查询SN"].Result ?? string.Empty;
var sn2 = stringTasks["上传结果SN"].Result ?? string.Empty;
var runStatus = intTasks["运行状态"].Result;
var machineModel = intTasks["设备模式"].Result;
var onlineStatus = intTasks["设备在线状态"].Result;
var produceModel = intTasks["生产模式"].Result;
var screwGunProgram = intTasks["螺钉枪程序号"].Result;
var actualOutput = intTasks["实际产量"].Result;
var productTotalResult = intTasks["产品总结果"].Result;
var screw1Result = intTasks["1#结果"].Result;
var screw2Result = intTasks["2#结果"].Result;
var screw3Result = intTasks["3#结果"].Result;
var screw4Result = intTasks["4#结果"].Result;
var screw1Torque = realTasks["1#扭矩"].Result;
var screw2Torque = realTasks["2#扭矩"].Result;
var screw3Torque = realTasks["3#扭矩"].Result;
var screw4Torque = realTasks["4#扭矩"].Result;
var screw1Angle = realTasks["1#转角"].Result;
var screw2Angle = realTasks["2#转角"].Result;
var screw3Angle = realTasks["3#转角"].Result;
var screw4Angle = realTasks["4#转角"].Result;
var screw1Depth = realTasks["1#深度"].Result;
var screw2Depth = realTasks["2#深度"].Result;
var screw3Depth = realTasks["3#深度"].Result;
var screw4Depth = realTasks["4#深度"].Result;
var cycleTime = realTasks["节拍时间"].Result;
// 4. 业务逻辑转换
var reworkFlag = produceModel == 2 ? "1" : "0";
var produceModelDesc = produceModel switch
{
1 => "点检模式",
2 => "返工模式",
4 => "样件模式",
5 => "正常模式",
_ => produceModel.ToString()
};
var onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线";
var qualificationFlag = productTotalResult == 1 ? "1" : "2";
// 5. 构建完整实体
return new PlcProductionData
{
// 基础字段
PlcIp = ip,
OccurTime = now,
LineCode = "line2",
WorkstationCode = workstationCode,
WorkstationName = "HV连接器装配工位",
ProductModel = productModel,
ProductName = productName,
ProductCode = sn1,
SN1 = sn1,
SN2 = sn2,
ReworkFlag = reworkFlag,
Automanual = machineModel,
Runstatus = runStatus,
OnlineStatus = onlineStatusDesc,
ProduceModel = produceModelDesc,
QualificationFlag = qualificationFlag,
ProductionCycle = (int)Math.Round(cycleTime),
CreatedBy = "PLC",
CreatedTime = now,
// 螺丝1-4参数完整赋值
Screw1Result = screw1Result.ToString(),
Screw1Torque = screw1Torque.ToString("F2"),
Screw1Depth = screw1Depth.ToString("F2"),
Screw1Angle = screw1Angle.ToString("F2"),
Screw2Result = screw2Result.ToString(),
Screw2Torque = screw2Torque.ToString("F2"),
Screw2Depth = screw2Depth.ToString("F2"),
Screw2Angle = screw2Angle.ToString("F2"),
Screw3Result = screw3Result.ToString(),
Screw3Torque = screw3Torque.ToString("F2"),
Screw3Depth = screw3Depth.ToString("F2"),
Screw3Angle = screw3Angle.ToString("F2"),
Screw4Result = screw4Result.ToString(),
Screw4Torque = screw4Torque.ToString("F2"),
Screw4Depth = screw4Depth.ToString("F2"),
Screw4Angle = screw4Angle.ToString("F2"),
};
}
catch (Exception ex)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] OP1011读取异常{ex.Message}");
return null;
}
}
/// <summary>
/// 读取OP1012数据Ring terminal装配工位DB1001
/// </summary>
public async Task<PlcProductionData> ReadOP1012DataAsync(Plc plc, string ip, string workstationCode)
{
// 前置校验:快速失败
if (plc == null || !plc.IsConnected) return null;
if (string.IsNullOrWhiteSpace(ip) || string.IsNullOrWhiteSpace(workstationCode))
throw new ArgumentNullException("IP或工位编码不能为空");
try
{
// 1. 批量创建并行读取任务
var stringTasks = new Dictionary<string, Task<string>>
{
{ "产品型号", ReadPlcStringAsync(plc, _op1012StringMap["产品型号"].Addr, _op1012StringMap["产品型号"].Len) },
{ "产品名称", ReadPlcStringAsync(plc, _op1012StringMap["产品名称"].Addr, _op1012StringMap["产品名称"].Len) },
{ "查询SN", ReadPlcStringAsync(plc, _op1012StringMap["查询SN"].Addr, _op1012StringMap["查询SN"].Len) },
{ "上传SN", ReadPlcStringAsync(plc, _op1012StringMap["上传SN"].Addr, _op1012StringMap["上传SN"].Len) }
};
var intTasks = new Dictionary<string, Task<int>>
{
{ "运行状态", ReadPlcIntAsync(plc, _op1012IntMap["运行状态"]) },
{ "设备模式", ReadPlcIntAsync(plc, _op1012IntMap["设备模式"]) },
{ "设备在线状态", ReadPlcIntAsync(plc, _op1012IntMap["设备在线状态"]) },
{ "生产模式", ReadPlcIntAsync(plc, _op1012IntMap["生产模式"]) },
{ "螺钉枪程序号", ReadPlcIntAsync(plc, _op1012IntMap["螺钉枪程序号"]) },
{ "实际产量", ReadPlcIntAsync(plc, _op1012IntMap["实际产量"]) },
{ "产品总结果", ReadPlcIntAsync(plc, _op1012IntMap["产品总结果"]) },
{ "1#结果", ReadPlcIntAsync(plc, _op1012IntMap["1#结果"]) },
{ "2#结果", ReadPlcIntAsync(plc, _op1012IntMap["2#结果"]) }
};
var realTasks = new Dictionary<string, Task<float>>
{
{ "1#扭矩", ReadPlcRealAsync(plc, _op1012IntMap["1#扭矩"]) },
{ "2#扭矩", ReadPlcRealAsync(plc, _op1012IntMap["2#扭矩"]) },
{ "1#转角", ReadPlcRealAsync(plc, _op1012IntMap["1#转角"]) },
{ "2#转角", ReadPlcRealAsync(plc, _op1012IntMap["2#转角"]) },
{ "1#深度", ReadPlcRealAsync(plc, _op1012IntMap["1#深度"]) },
{ "2#深度", ReadPlcRealAsync(plc, _op1012IntMap["2#深度"]) },
{ "节拍时间", ReadPlcRealAsync(plc, _op1012IntMap["节拍时间"]) }
};
// 2. 并行等待所有任务完成
var allTasks = new List<Task>();
allTasks.AddRange(stringTasks.Values);
allTasks.AddRange(intTasks.Values);
allTasks.AddRange(realTasks.Values);
await Task.WhenAll(allTasks).ConfigureAwait(false);
// 3. 提取结果
var now = DateTime.Now;
var productModel = stringTasks["产品型号"].Result ?? string.Empty;
var productName = stringTasks["产品名称"].Result ?? string.Empty;
var sn1 = stringTasks["查询SN"].Result ?? string.Empty;
var sn2 = stringTasks["上传SN"].Result ?? string.Empty;
var runStatus = intTasks["运行状态"].Result;
var machineModel = intTasks["设备模式"].Result;
var onlineStatus = intTasks["设备在线状态"].Result;
var produceModel = intTasks["生产模式"].Result;
var screwGunProgram = intTasks["螺钉枪程序号"].Result;
var actualOutput = intTasks["实际产量"].Result;
var productTotalResult = intTasks["产品总结果"].Result;
var screw1Result = intTasks["1#结果"].Result;
var screw2Result = intTasks["2#结果"].Result;
var screw1Torque = realTasks["1#扭矩"].Result;
var screw2Torque = realTasks["2#扭矩"].Result;
var screw1Angle = realTasks["1#转角"].Result;
var screw2Angle = realTasks["2#转角"].Result;
var screw1Depth = realTasks["1#深度"].Result;
var screw2Depth = realTasks["2#深度"].Result;
var cycleTime = realTasks["节拍时间"].Result;
// 4. 业务逻辑转换
var reworkFlag = produceModel == 2 ? "1" : "0";
var produceModelDesc = produceModel switch
{
1 => "点检模式",
2 => "返工模式",
4 => "样件模式",
5 => "正常模式",
_ => produceModel.ToString()
};
var onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线";
var qualificationFlag = productTotalResult == 1 ? "1" : "2";
// 5. 构建完整实体
return new PlcProductionData
{
// 基础字段
PlcIp = ip,
OccurTime = now,
LineCode = "line2",
WorkstationCode = workstationCode,
WorkstationName = "Ring terminal装配工位",
ProductModel = productModel,
ProductName = productName,
ProductCode = sn1,
SN1 = sn1,
SN2 = sn2,
ReworkFlag = reworkFlag,
Automanual = machineModel,
Runstatus = runStatus,
OnlineStatus = onlineStatusDesc,
ProduceModel = produceModelDesc,
QualificationFlag = qualificationFlag,
ProductionCycle = (int)Math.Round(cycleTime),
CreatedBy = "PLC",
CreatedTime = now,
// 螺丝1-2参数完整赋值
Screw1Result = screw1Result.ToString(),
Screw1Torque = screw1Torque.ToString("F2"),
Screw1Depth = screw1Depth.ToString("F2"),
Screw1Angle = screw1Angle.ToString("F2"),
Screw2Result = screw2Result.ToString(),
Screw2Torque = screw2Torque.ToString("F2"),
Screw2Depth = screw2Depth.ToString("F2"),
Screw2Angle = screw2Angle.ToString("F2"),
};
}
catch (Exception ex)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] OP1012读取异常{ex.Message}");
return null;
}
}
/// <summary>
/// 读取OP102数据等离子处理工位DB1001
/// </summary>
public async Task<PlcProductionData> ReadOP102DataAsync(Plc plc, string ip, string workstationCode)
{
// 前置校验:快速失败
if (plc == null || !plc.IsConnected) return null;
if (string.IsNullOrWhiteSpace(ip) || string.IsNullOrWhiteSpace(workstationCode))
throw new ArgumentNullException("IP或工位编码不能为空");
try
{
// 1. 批量创建并行读取任务
var stringTasks = new Dictionary<string, Task<string>>
{
{ "产品型号", ReadPlcStringAsync(plc, _op102StringMap["产品型号"].Addr, _op102StringMap["产品型号"].Len) },
{ "产品名称", ReadPlcStringAsync(plc, _op102StringMap["产品名称"].Addr, _op102StringMap["产品名称"].Len) },
{ "查询SN", ReadPlcStringAsync(plc, _op102StringMap["查询SN"].Addr, _op102StringMap["查询SN"].Len) },
{ "上传结果SN", ReadPlcStringAsync(plc, _op102StringMap["上传结果SN"].Addr, _op102StringMap["上传结果SN"].Len) }
};
var intTasks = new Dictionary<string, Task<int>>
{
{ "运行状态", ReadPlcIntAsync(plc, _op102IntMap["运行状态"]) },
{ "设备模式", ReadPlcIntAsync(plc, _op102IntMap["设备模式"]) },
{ "设备在线状态", ReadPlcIntAsync(plc, _op102IntMap["设备在线状态"]) },
{ "生产模式", ReadPlcIntAsync(plc, _op102IntMap["生产模式"]) },
{ "实际产量", ReadPlcIntAsync(plc, _op102IntMap["实际产量"]) },
{ "站位结果", ReadPlcIntAsync(plc, _op102IntMap["站位结果"]) },
{ "托盘号", ReadPlcIntAsync(plc, _op102IntMap["托盘号"]) }
};
var realTasks = new Dictionary<string, Task<float>>
{
{ "节拍时间", ReadPlcRealAsync(plc, _op102IntMap["节拍时间"]) }
};
// 2. 并行等待所有任务完成
var allTasks = new List<Task>();
allTasks.AddRange(stringTasks.Values);
allTasks.AddRange(intTasks.Values);
allTasks.AddRange(realTasks.Values);
await Task.WhenAll(allTasks).ConfigureAwait(false);
// 3. 提取结果
var now = DateTime.Now;
var productModel = stringTasks["产品型号"].Result ?? string.Empty;
var productName = stringTasks["产品名称"].Result ?? string.Empty;
var sn1 = stringTasks["查询SN"].Result ?? string.Empty;
var sn2 = stringTasks["上传结果SN"].Result ?? string.Empty;
var runStatus = intTasks["运行状态"].Result;
var machineModel = intTasks["设备模式"].Result;
var onlineStatus = intTasks["设备在线状态"].Result;
var produceModel = intTasks["生产模式"].Result;
var actualOutput = intTasks["实际产量"].Result;
var stationResult = intTasks["站位结果"].Result;
var trayNo = intTasks["托盘号"].Result.ToString();
var cycleTime = realTasks["节拍时间"].Result;
// 4. 业务逻辑转换
var reworkFlag = produceModel == 2 ? "1" : "0";
var produceModelDesc = produceModel switch
{
1 => "点检模式",
2 => "返工模式",
4 => "样件模式",
5 => "正常模式",
_ => produceModel.ToString()
};
var onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线";
var qualificationFlag = stationResult == 1 ? "1" : "2";
// 6. 构建完整实体
return new PlcProductionData
{
// 基础字段
PlcIp = ip,
OccurTime = now,
LineCode = "line2",
WorkstationCode = workstationCode,
WorkstationName = "等离子处理工位",
ProductModel = productModel,
ProductName = productName,
ProductCode = sn1,
SN1 = sn1,
SN2 = sn2,
TrayNo = trayNo,
ReworkFlag = reworkFlag,
Automanual = machineModel,
Runstatus = runStatus,
OnlineStatus = onlineStatusDesc,
ProduceModel = produceModelDesc,
QualificationFlag = qualificationFlag,
ProductionCycle = (int)Math.Round(cycleTime),
CreatedBy = "PLC",
CreatedTime = now,
};
}
catch (Exception ex)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] OP102读取异常{ex.Message}");
return null;
}
}
/// <summary>
/// 读取OP110-1数据点胶封胶Q3-3636工位DB1001
/// </summary>
public async Task<PlcProductionData> ReadOP110_1DataAsync(Plc plc, string ip, string workstationCode)
{
// 前置校验:快速失败
if (plc == null || !plc.IsConnected) return null;
if (string.IsNullOrWhiteSpace(ip) || string.IsNullOrWhiteSpace(workstationCode))
throw new ArgumentNullException("IP或工位编码不能为空");
try
{
// 1. 批量创建并行读取任务
var stringTasks = new Dictionary<string, Task<string>>
{
{ "产品型号", ReadPlcStringAsync(plc, _op110_1StringMap["产品型号"].Addr, _op110_1StringMap["产品型号"].Len) },
{ "产品名称", ReadPlcStringAsync(plc, _op110_1StringMap["产品名称"].Addr, _op110_1StringMap["产品名称"].Len) },
{ "查询SN", ReadPlcStringAsync(plc, _op110_1StringMap["查询SN"].Addr, _op110_1StringMap["查询SN"].Len) },
{ "上传结果SN", ReadPlcStringAsync(plc, _op110_1StringMap["上传结果SN"].Addr, _op110_1StringMap["上传结果SN"].Len) }
};
var intTasks = new Dictionary<string, Task<int>>
{
{ "运行状态", ReadPlcIntAsync(plc, _op110_1IntMap["运行状态"]) },
{ "设备模式", ReadPlcIntAsync(plc, _op110_1IntMap["设备模式"]) },
{ "设备在线状态", ReadPlcIntAsync(plc, _op110_1IntMap["设备在线状态"]) },
{ "生产模式", ReadPlcIntAsync(plc, _op110_1IntMap["生产模式"]) },
{ "实际产量", ReadPlcIntAsync(plc, _op110_1IntMap["实际产量"]) },
{ "相机结果", ReadPlcIntAsync(plc, _op110_1IntMap["相机结果"]) },
{ "站位结果", ReadPlcIntAsync(plc, _op110_1IntMap["站位结果"]) },
{ "托盘号", ReadPlcIntAsync(plc, _op110_1IntMap["托盘号"]) }
};
var realTasks = new Dictionary<string, Task<float>>
{
{ "节拍时间", ReadPlcRealAsync(plc, _op110_1IntMap["节拍时间"]) }
};
// 2. 并行等待所有任务完成
var allTasks = new List<Task>();
allTasks.AddRange(stringTasks.Values);
allTasks.AddRange(intTasks.Values);
allTasks.AddRange(realTasks.Values);
await Task.WhenAll(allTasks).ConfigureAwait(false);
// 3. 提取结果
var now = DateTime.Now;
var productModel = stringTasks["产品型号"].Result ?? string.Empty;
var productName = stringTasks["产品名称"].Result ?? string.Empty;
var sn1 = stringTasks["查询SN"].Result ?? string.Empty;
var sn2 = stringTasks["上传结果SN"].Result ?? string.Empty;
var runStatus = intTasks["运行状态"].Result;
var machineModel = intTasks["设备模式"].Result;
var onlineStatus = intTasks["设备在线状态"].Result;
var produceModel = intTasks["生产模式"].Result;
var actualOutput = intTasks["实际产量"].Result;
var cameraResult = intTasks["相机结果"].Result;
var stationResult = intTasks["站位结果"].Result;
var trayNo = intTasks["托盘号"].Result.ToString();
var cycleTime = realTasks["节拍时间"].Result;
// 4. 业务逻辑转换
var reworkFlag = produceModel == 2 ? "1" : "0";
var produceModelDesc = produceModel switch
{
1 => "点检模式",
2 => "返工模式",
4 => "样件模式",
5 => "正常模式",
_ => produceModel.ToString()
};
var onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线";
var qualificationFlag = stationResult == 1 ? "1" : "2";
// 6. 构建完整实体
return new PlcProductionData
{
// 基础字段
PlcIp = ip,
OccurTime = now,
LineCode = "line2",
WorkstationCode = workstationCode,
WorkstationName = "点胶封胶Q3-3636工位",
ProductModel = productModel,
ProductName = productName,
ProductCode = sn1,
SN1 = sn1,
SN2 = sn2,
TrayNo = trayNo,
ReworkFlag = reworkFlag,
Automanual = machineModel,
Runstatus = runStatus,
OnlineStatus = onlineStatusDesc,
ProduceModel = produceModelDesc,
QualificationFlag = qualificationFlag,
ProductionCycle = (int)Math.Round(cycleTime),
CreatedBy = "PLC",
CreatedTime = now,
CameraResult = cameraResult == 1 ? "1" : "2", // 相机结果映射
};
}
catch (Exception ex)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] OP110-1读取异常{ex.Message}");
return null;
}
}
/// <summary>
/// 读取OP110-2数据盖板组装&拧紧工位DB1001
/// </summary>
public async Task<PlcProductionData> ReadOP110_2DataAsync(Plc plc, string ip, string workstationCode)
{
// 前置校验:快速失败
if (plc == null || !plc.IsConnected) return null;
if (string.IsNullOrWhiteSpace(ip) || string.IsNullOrWhiteSpace(workstationCode))
throw new ArgumentNullException("IP或工位编码不能为空");
try
{
// 1. 批量创建并行读取任务
var stringTasks = new Dictionary<string, Task<string>>
{
{ "产品型号", ReadPlcStringAsync(plc, _op110_2StringMap["产品型号"].Addr, _op110_2StringMap["产品型号"].Len) },
{ "产品名称", ReadPlcStringAsync(plc, _op110_2StringMap["产品名称"].Addr, _op110_2StringMap["产品名称"].Len) },
{ "合装工位查询SN", ReadPlcStringAsync(plc, _op110_2StringMap["合装工位查询SN"].Addr, _op110_2StringMap["合装工位查询SN"].Len) },
{ "拧紧工位上传结果SN", ReadPlcStringAsync(plc, _op110_2StringMap["拧紧工位上传结果SN"].Addr, _op110_2StringMap["拧紧工位上传结果SN"].Len) }
};
var intTasks = new Dictionary<string, Task<int>>
{
{ "运行状态", ReadPlcIntAsync(plc, _op110_2IntMap["运行状态"]) },
{ "设备模式", ReadPlcIntAsync(plc, _op110_2IntMap["设备模式"]) },
{ "设备在线状态", ReadPlcIntAsync(plc, _op110_2IntMap["设备在线状态"]) },
{ "生产模式", ReadPlcIntAsync(plc, _op110_2IntMap["生产模式"]) },
{ "实际产量", ReadPlcIntAsync(plc, _op110_2IntMap["实际产量"]) },
{ "产品总结果", ReadPlcIntAsync(plc, _op110_2IntMap["产品总结果"]) },
{ "3#螺丝结果", ReadPlcIntAsync(plc, _op110_2IntMap["3#螺丝结果"]) },
{ "5#螺丝结果", ReadPlcIntAsync(plc, _op110_2IntMap["5#螺丝结果"]) },
{ "6#螺丝结果", ReadPlcIntAsync(plc, _op110_2IntMap["6#螺丝结果"]) },
{ "1#螺丝结果", ReadPlcIntAsync(plc, _op110_2IntMap["1#螺丝结果"]) },
{ "2#螺丝结果", ReadPlcIntAsync(plc, _op110_2IntMap["2#螺丝结果"]) },
{ "4#螺丝结果", ReadPlcIntAsync(plc, _op110_2IntMap["4#螺丝结果"]) },
{ "7#螺丝结果", ReadPlcIntAsync(plc, _op110_2IntMap["7#螺丝结果"]) },
{ "托盘号", ReadPlcIntAsync(plc, _op110_2IntMap["托盘号"]) }
};
var realTasks = new Dictionary<string, Task<float>>
{
{ "3#扭矩", ReadPlcRealAsync(plc, _op110_2IntMap["3#扭矩"]) },
{ "3#深度", ReadPlcRealAsync(plc, _op110_2IntMap["3#深度"]) },
{ "3#角度", ReadPlcRealAsync(plc, _op110_2IntMap["3#角度"]) },
{ "3#拧紧时间", ReadPlcRealAsync(plc, _op110_2IntMap["3#拧紧时间"]) },
{ "5#扭矩", ReadPlcRealAsync(plc, _op110_2IntMap["5#扭矩"]) },
{ "5#深度", ReadPlcRealAsync(plc, _op110_2IntMap["5#深度"]) },
{ "5#角度", ReadPlcRealAsync(plc, _op110_2IntMap["5#角度"]) },
{ "5#拧紧时间", ReadPlcRealAsync(plc, _op110_2IntMap["5#拧紧时间"]) },
{ "6#扭矩", ReadPlcRealAsync(plc, _op110_2IntMap["6#扭矩"]) },
{ "6#深度", ReadPlcRealAsync(plc, _op110_2IntMap["6#深度"]) },
{ "6#角度", ReadPlcRealAsync(plc, _op110_2IntMap["6#角度"]) },
{ "6#拧紧时间", ReadPlcRealAsync(plc, _op110_2IntMap["6#拧紧时间"]) },
{ "1#扭矩", ReadPlcRealAsync(plc, _op110_2IntMap["1#扭矩"]) },
{ "1#深度", ReadPlcRealAsync(plc, _op110_2IntMap["1#深度"]) },
{ "1#角度", ReadPlcRealAsync(plc, _op110_2IntMap["1#角度"]) },
{ "1#拧紧时间", ReadPlcRealAsync(plc, _op110_2IntMap["1#拧紧时间"]) },
{ "2#扭矩", ReadPlcRealAsync(plc, _op110_2IntMap["2#扭矩"]) },
{ "2#深度", ReadPlcRealAsync(plc, _op110_2IntMap["2#深度"]) },
{ "2#角度", ReadPlcRealAsync(plc, _op110_2IntMap["2#角度"]) },
{ "2#拧紧时间", ReadPlcRealAsync(plc, _op110_2IntMap["2#拧紧时间"]) },
{ "4#扭矩", ReadPlcRealAsync(plc, _op110_2IntMap["4#扭矩"]) },
{ "4#深度", ReadPlcRealAsync(plc, _op110_2IntMap["4#深度"]) },
{ "4#角度", ReadPlcRealAsync(plc, _op110_2IntMap["4#角度"]) },
{ "4#拧紧时间", ReadPlcRealAsync(plc, _op110_2IntMap["4#拧紧时间"]) },
{ "7#扭矩", ReadPlcRealAsync(plc, _op110_2IntMap["7#扭矩"]) },
{ "7#深度", ReadPlcRealAsync(plc, _op110_2IntMap["7#深度"]) },
{ "7#角度", ReadPlcRealAsync(plc, _op110_2IntMap["7#角度"]) },
{ "7#拧紧时间", ReadPlcRealAsync(plc, _op110_2IntMap["7#拧紧时间"]) },
{ "节拍时间", ReadPlcRealAsync(plc, _op110_2IntMap["节拍时间"]) }
};
// 2. 并行等待所有任务完成
var allTasks = new List<Task>();
allTasks.AddRange(stringTasks.Values);
allTasks.AddRange(intTasks.Values);
allTasks.AddRange(realTasks.Values);
await Task.WhenAll(allTasks).ConfigureAwait(false);
// 3. 提取结果
var now = DateTime.Now;
var productModel = stringTasks["产品型号"].Result ?? string.Empty;
var productName = stringTasks["产品名称"].Result ?? string.Empty;
var sn1 = stringTasks["合装工位查询SN"].Result ?? string.Empty;
var sn2 = stringTasks["拧紧工位上传结果SN"].Result ?? string.Empty;
var runStatus = intTasks["运行状态"].Result;
var machineModel = intTasks["设备模式"].Result;
var onlineStatus = intTasks["设备在线状态"].Result;
var produceModel = intTasks["生产模式"].Result;
var actualOutput = intTasks["实际产量"].Result;
var productTotalResult = intTasks["产品总结果"].Result;
var screw1Result = intTasks["1#螺丝结果"].Result;
var screw2Result = intTasks["2#螺丝结果"].Result;
var screw3Result = intTasks["3#螺丝结果"].Result;
var screw4Result = intTasks["4#螺丝结果"].Result;
var screw5Result = intTasks["5#螺丝结果"].Result;
var screw6Result = intTasks["6#螺丝结果"].Result;
var screw7Result = intTasks["7#螺丝结果"].Result;
var trayNo = intTasks["托盘号"].Result.ToString();
var screw1Torque = realTasks["1#扭矩"].Result;
var screw1Depth = realTasks["1#深度"].Result;
var screw1Angle = realTasks["1#角度"].Result;
var screw1TightenTime = realTasks["1#拧紧时间"].Result;
var screw2Torque = realTasks["2#扭矩"].Result;
var screw2Depth = realTasks["2#深度"].Result;
var screw2Angle = realTasks["2#角度"].Result;
var screw2TightenTime = realTasks["2#拧紧时间"].Result;
var screw3Torque = realTasks["3#扭矩"].Result;
var screw3Depth = realTasks["3#深度"].Result;
var screw3Angle = realTasks["3#角度"].Result;
var screw3TightenTime = realTasks["3#拧紧时间"].Result;
var screw4Torque = realTasks["4#扭矩"].Result;
var screw4Depth = realTasks["4#深度"].Result;
var screw4Angle = realTasks["4#角度"].Result;
var screw4TightenTime = realTasks["4#拧紧时间"].Result;
var screw5Torque = realTasks["5#扭矩"].Result;
var screw5Depth = realTasks["5#深度"].Result;
var screw5Angle = realTasks["5#角度"].Result;
var screw5TightenTime = realTasks["5#拧紧时间"].Result;
var screw6Torque = realTasks["6#扭矩"].Result;
var screw6Depth = realTasks["6#深度"].Result;
var screw6Angle = realTasks["6#角度"].Result;
var screw6TightenTime = realTasks["6#拧紧时间"].Result;
var screw7Torque = realTasks["7#扭矩"].Result;
var screw7Depth = realTasks["7#深度"].Result;
var screw7Angle = realTasks["7#角度"].Result;
var screw7TightenTime = realTasks["7#拧紧时间"].Result;
var cycleTime = realTasks["节拍时间"].Result;
// 4. 业务逻辑转换
var reworkFlag = produceModel == 2 ? "1" : "0";
var produceModelDesc = produceModel switch
{
1 => "点检模式",
2 => "返工模式",
4 => "样件模式",
5 => "正常模式",
_ => produceModel.ToString()
};
var onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线";
var qualificationFlag = productTotalResult == 1 ? "1" : "2";
// 6. 构建完整实体
return new PlcProductionData
{
// 基础字段
PlcIp = ip,
OccurTime = now,
LineCode = "line2",
WorkstationCode = workstationCode,
WorkstationName = "盖板组装&拧紧工位",
ProductModel = productModel,
ProductName = productName,
ProductCode = sn1,
SN1 = sn1,
SN2 = sn2,
TrayNo = trayNo,
ReworkFlag = reworkFlag,
Automanual = machineModel,
Runstatus = runStatus,
OnlineStatus = onlineStatusDesc,
ProduceModel = produceModelDesc,
QualificationFlag = qualificationFlag,
ProductionCycle = (int)Math.Round(cycleTime),
CreatedBy = "PLC",
CreatedTime = now,
// 螺丝1-7参数完整赋值
Screw1Result = screw1Result.ToString(),
Screw1Torque = screw1Torque.ToString("F2"),
Screw1Depth = screw1Depth.ToString("F2"),
Screw1Angle = screw1Angle.ToString("F2"),
Screw1TightenTime = screw1TightenTime.ToString("F2"),
Screw2Result = screw2Result.ToString(),
Screw2Torque = screw2Torque.ToString("F2"),
Screw2Depth = screw2Depth.ToString("F2"),
Screw2Angle = screw2Angle.ToString("F2"),
Screw2TightenTime = screw2TightenTime.ToString("F2"),
Screw3Result = screw3Result.ToString(),
Screw3Torque = screw3Torque.ToString("F2"),
Screw3Depth = screw3Depth.ToString("F2"),
Screw3Angle = screw3Angle.ToString("F2"),
Screw3TightenTime = screw3TightenTime.ToString("F2"),
Screw4Result = screw4Result.ToString(),
Screw4Torque = screw4Torque.ToString("F2"),
Screw4Depth = screw4Depth.ToString("F2"),
Screw4Angle = screw4Angle.ToString("F2"),
Screw4TightenTime = screw4TightenTime.ToString("F2"),
Screw5Result = screw5Result.ToString(),
Screw5Torque = screw5Torque.ToString("F2"),
Screw5Depth = screw5Depth.ToString("F2"),
Screw5Angle = screw5Angle.ToString("F2"),
Screw5TightenTime = screw5TightenTime.ToString("F2"),
Screw6Result = screw6Result.ToString(),
Screw6Torque = screw6Torque.ToString("F2"),
Screw6Depth = screw6Depth.ToString("F2"),
Screw6Angle = screw6Angle.ToString("F2"),
Screw6TightenTime = screw6TightenTime.ToString("F2"),
Screw7Result = screw7Result.ToString(),
Screw7Torque = screw7Torque.ToString("F2"),
Screw7Depth = screw7Depth.ToString("F2"),
Screw7Angle = screw7Angle.ToString("F2"),
Screw7TightenTime = screw7TightenTime.ToString("F2"),
};
}
catch (Exception ex)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] OP110-2读取异常{ex.Message}");
return null;
}
}
/// <summary>
/// 读取OP110-3数据盖板拧紧工位DB1001
/// </summary>
public async Task<PlcProductionData> ReadOP110_3DataAsync(Plc plc, string ip, string workstationCode)
{
// 前置校验:快速失败
if (plc == null || !plc.IsConnected) return null;
if (string.IsNullOrWhiteSpace(ip) || string.IsNullOrWhiteSpace(workstationCode))
throw new ArgumentNullException("IP或工位编码不能为空");
try
{
// 1. 批量创建并行读取任务
var stringTasks = new Dictionary<string, Task<string>>
{
{ "产品型号", ReadPlcStringAsync(plc, _op110_3StringMap["产品型号"].Addr, _op110_3StringMap["产品型号"].Len) },
{ "产品名称", ReadPlcStringAsync(plc, _op110_3StringMap["产品名称"].Addr, _op110_3StringMap["产品名称"].Len) },
{ "查询SN", ReadPlcStringAsync(plc, _op110_3StringMap["查询SN"].Addr, _op110_3StringMap["查询SN"].Len) },
{ "保存SN", ReadPlcStringAsync(plc, _op110_3StringMap["保存SN"].Addr, _op110_3StringMap["保存SN"].Len) }
};
var intTasks = new Dictionary<string, Task<int>>
{
{ "运行状态", ReadPlcIntAsync(plc, _op110_3IntMap["运行状态"]) },
{ "设备模式", ReadPlcIntAsync(plc, _op110_3IntMap["设备模式"]) },
{ "设备在线状态", ReadPlcIntAsync(plc, _op110_3IntMap["设备在线状态"]) },
{ "生产模式", ReadPlcIntAsync(plc, _op110_3IntMap["生产模式"]) },
{ "实际产量", ReadPlcIntAsync(plc, _op110_3IntMap["实际产量"]) },
{ "产品总结果", ReadPlcIntAsync(plc, _op110_3IntMap["产品总结果"]) },
{ "1#螺丝结果", ReadPlcIntAsync(plc, _op110_3IntMap["1#螺丝结果"]) },
{ "2#螺丝结果", ReadPlcIntAsync(plc, _op110_3IntMap["2#螺丝结果"]) },
{ "3#螺丝结果", ReadPlcIntAsync(plc, _op110_3IntMap["3#螺丝结果"]) },
{ "4#螺丝结果", ReadPlcIntAsync(plc, _op110_3IntMap["4#螺丝结果"]) },
{ "5#螺丝结果", ReadPlcIntAsync(plc, _op110_3IntMap["5#螺丝结果"]) },
{ "6#螺丝结果", ReadPlcIntAsync(plc, _op110_3IntMap["6#螺丝结果"]) },
{ "7#螺丝结果", ReadPlcIntAsync(plc, _op110_3IntMap["7#螺丝结果"]) },
{ "托盘号", ReadPlcIntAsync(plc, _op110_3IntMap["托盘号"]) }
};
var realTasks = new Dictionary<string, Task<float>>
{
{ "1#扭矩", ReadPlcRealAsync(plc, _op110_3IntMap["1#扭矩"]) },
{ "1#深度", ReadPlcRealAsync(plc, _op110_3IntMap["1#深度"]) },
{ "1#角度", ReadPlcRealAsync(plc, _op110_3IntMap["1#角度"]) },
{ "1#拧紧时间", ReadPlcRealAsync(plc, _op110_3IntMap["1#拧紧时间"]) },
{ "2#扭矩", ReadPlcRealAsync(plc, _op110_3IntMap["2#扭矩"]) },
{ "2#深度", ReadPlcRealAsync(plc, _op110_3IntMap["2#深度"]) },
{ "2#角度", ReadPlcRealAsync(plc, _op110_3IntMap["2#角度"]) },
{ "2#拧紧时间", ReadPlcRealAsync(plc, _op110_3IntMap["2#拧紧时间"]) },
{ "3#扭矩", ReadPlcRealAsync(plc, _op110_3IntMap["3#扭矩"]) },
{ "3#深度", ReadPlcRealAsync(plc, _op110_3IntMap["3#深度"]) },
{ "3#角度", ReadPlcRealAsync(plc, _op110_3IntMap["3#角度"]) },
{ "3#拧紧时间", ReadPlcRealAsync(plc, _op110_3IntMap["3#拧紧时间"]) },
{ "4#扭矩", ReadPlcRealAsync(plc, _op110_3IntMap["4#扭矩"]) },
{ "4#深度", ReadPlcRealAsync(plc, _op110_3IntMap["4#深度"]) },
{ "4#角度", ReadPlcRealAsync(plc, _op110_3IntMap["4#角度"]) },
{ "4#拧紧时间", ReadPlcRealAsync(plc, _op110_3IntMap["4#拧紧时间"]) },
{ "5#扭矩", ReadPlcRealAsync(plc, _op110_3IntMap["5#扭矩"]) },
{ "5#深度", ReadPlcRealAsync(plc, _op110_3IntMap["5#深度"]) },
{ "5#角度", ReadPlcRealAsync(plc, _op110_3IntMap["5#角度"]) },
{ "5#拧紧时间", ReadPlcRealAsync(plc, _op110_3IntMap["5#拧紧时间"]) },
{ "6#扭矩", ReadPlcRealAsync(plc, _op110_3IntMap["6#扭矩"]) },
{ "6#深度", ReadPlcRealAsync(plc, _op110_3IntMap["6#深度"]) },
{ "6#角度", ReadPlcRealAsync(plc, _op110_3IntMap["6#角度"]) },
{ "6#拧紧时间", ReadPlcRealAsync(plc, _op110_3IntMap["6#拧紧时间"]) },
{ "7#扭矩", ReadPlcRealAsync(plc, _op110_3IntMap["7#扭矩"]) },
{ "7#深度", ReadPlcRealAsync(plc, _op110_3IntMap["7#深度"]) },
{ "7#角度", ReadPlcRealAsync(plc, _op110_3IntMap["7#角度"]) },
{ "7#拧紧时间", ReadPlcRealAsync(plc, _op110_3IntMap["7#拧紧时间"]) },
{ "节拍时间", ReadPlcRealAsync(plc, _op110_3IntMap["节拍时间"]) }
};
// 2. 并行等待所有任务完成
var allTasks = new List<Task>();
allTasks.AddRange(stringTasks.Values);
allTasks.AddRange(intTasks.Values);
allTasks.AddRange(realTasks.Values);
await Task.WhenAll(allTasks).ConfigureAwait(false);
// 3. 提取结果
var now = DateTime.Now;
var productModel = stringTasks["产品型号"].Result ?? string.Empty;
var productName = stringTasks["产品名称"].Result ?? string.Empty;
var sn1 = stringTasks["查询SN"].Result ?? string.Empty;
var sn2 = stringTasks["保存SN"].Result ?? string.Empty;
var runStatus = intTasks["运行状态"].Result;
var machineModel = intTasks["设备模式"].Result;
var onlineStatus = intTasks["设备在线状态"].Result;
var produceModel = intTasks["生产模式"].Result;
var actualOutput = intTasks["实际产量"].Result;
var productTotalResult = intTasks["产品总结果"].Result;
var screw1Result = intTasks["1#螺丝结果"].Result;
var screw2Result = intTasks["2#螺丝结果"].Result;
var screw3Result = intTasks["3#螺丝结果"].Result;
var screw4Result = intTasks["4#螺丝结果"].Result;
var screw5Result = intTasks["5#螺丝结果"].Result;
var screw6Result = intTasks["6#螺丝结果"].Result;
var screw7Result = intTasks["7#螺丝结果"].Result;
var trayNo = intTasks["托盘号"].Result.ToString();
var screw1Torque = realTasks["1#扭矩"].Result;
var screw1Depth = realTasks["1#深度"].Result;
var screw1Angle = realTasks["1#角度"].Result;
var screw1TightenTime = realTasks["1#拧紧时间"].Result;
var screw2Torque = realTasks["2#扭矩"].Result;
var screw2Depth = realTasks["2#深度"].Result;
var screw2Angle = realTasks["2#角度"].Result;
var screw2TightenTime = realTasks["2#拧紧时间"].Result;
var screw3Torque = realTasks["3#扭矩"].Result;
var screw3Depth = realTasks["3#深度"].Result;
var screw3Angle = realTasks["3#角度"].Result;
var screw3TightenTime = realTasks["3#拧紧时间"].Result;
var screw4Torque = realTasks["4#扭矩"].Result;
var screw4Depth = realTasks["4#深度"].Result;
var screw4Angle = realTasks["4#角度"].Result;
var screw4TightenTime = realTasks["4#拧紧时间"].Result;
var screw5Torque = realTasks["5#扭矩"].Result;
var screw5Depth = realTasks["5#深度"].Result;
var screw5Angle = realTasks["5#角度"].Result;
var screw5TightenTime = realTasks["5#拧紧时间"].Result;
var screw6Torque = realTasks["6#扭矩"].Result;
var screw6Depth = realTasks["6#深度"].Result;
var screw6Angle = realTasks["6#角度"].Result;
var screw6TightenTime = realTasks["6#拧紧时间"].Result;
var screw7Torque = realTasks["7#扭矩"].Result;
var screw7Depth = realTasks["7#深度"].Result;
var screw7Angle = realTasks["7#角度"].Result;
var screw7TightenTime = realTasks["7#拧紧时间"].Result;
var cycleTime = realTasks["节拍时间"].Result;
// 4. 业务逻辑转换
var reworkFlag = produceModel == 2 ? "1" : "0";
var produceModelDesc = produceModel switch
{
1 => "点检模式",
2 => "返工模式",
4 => "样件模式",
5 => "正常模式",
_ => produceModel.ToString()
};
var onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线";
var qualificationFlag = productTotalResult == 1 ? "1" : "2";
// 5. 构建完整实体
return new PlcProductionData
{
// 基础字段
PlcIp = ip,
OccurTime = now,
LineCode = "line2",
WorkstationCode = workstationCode,
WorkstationName = "盖板拧紧工位",
ProductModel = productModel,
ProductName = productName,
ProductCode = sn1,
SN1 = sn1,
SN2 = sn2,
TrayNo = trayNo,
ReworkFlag = reworkFlag,
Automanual = machineModel,
Runstatus = runStatus,
OnlineStatus = onlineStatusDesc,
ProduceModel = produceModelDesc,
QualificationFlag = qualificationFlag,
ProductionCycle = (int)Math.Round(cycleTime),
CreatedBy = "PLC",
CreatedTime = now,
// 螺丝1-7参数完整赋值
Screw1Result = screw1Result.ToString(),
Screw1Torque = screw1Torque.ToString("F2"),
Screw1Depth = screw1Depth.ToString("F2"),
Screw1Angle = screw1Angle.ToString("F2"),
Screw1TightenTime = screw1TightenTime.ToString("F2"),
Screw2Result = screw2Result.ToString(),
Screw2Torque = screw2Torque.ToString("F2"),
Screw2Depth = screw2Depth.ToString("F2"),
Screw2Angle = screw2Angle.ToString("F2"),
Screw2TightenTime = screw2TightenTime.ToString("F2"),
Screw3Result = screw3Result.ToString(),
Screw3Torque = screw3Torque.ToString("F2"),
Screw3Depth = screw3Depth.ToString("F2"),
Screw3Angle = screw3Angle.ToString("F2"),
Screw3TightenTime = screw3TightenTime.ToString("F2"),
Screw4Result = screw4Result.ToString(),
Screw4Torque = screw4Torque.ToString("F2"),
Screw4Depth = screw4Depth.ToString("F2"),
Screw4Angle = screw4Angle.ToString("F2"),
Screw4TightenTime = screw4TightenTime.ToString("F2"),
Screw5Result = screw5Result.ToString(),
Screw5Torque = screw5Torque.ToString("F2"),
Screw5Depth = screw5Depth.ToString("F2"),
Screw5Angle = screw5Angle.ToString("F2"),
Screw5TightenTime = screw5TightenTime.ToString("F2"),
Screw6Result = screw6Result.ToString(),
Screw6Torque = screw6Torque.ToString("F2"),
Screw6Depth = screw6Depth.ToString("F2"),
Screw6Angle = screw6Angle.ToString("F2"),
Screw6TightenTime = screw6TightenTime.ToString("F2"),
Screw7Result = screw7Result.ToString(),
Screw7Torque = screw7Torque.ToString("F2"),
Screw7Depth = screw7Depth.ToString("F2"),
Screw7Angle = screw7Angle.ToString("F2"),
Screw7TightenTime = screw7TightenTime.ToString("F2"),
};
}
catch (Exception ex)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] OP110-3读取异常{ex.Message}");
return null;
}
}
/// <summary>
/// 读取OP115数据自动上下料到固化炉工位DB1001
/// </summary>
public async Task<PlcProductionData> ReadOP115DataAsync(Plc plc, string ip, string workstationCode)
{
// 前置校验:快速失败
if (plc == null || !plc.IsConnected) return null;
if (string.IsNullOrWhiteSpace(ip) || string.IsNullOrWhiteSpace(workstationCode))
throw new ArgumentNullException("IP或工位编码不能为空");
try
{
// 1. 批量创建并行读取任务
var stringTasks = new Dictionary<string, Task<string>>
{
{ "产品型号", ReadPlcStringAsync(plc, _op115StringMap["产品型号"].Addr, _op115StringMap["产品型号"].Len) },
{ "产品名称", ReadPlcStringAsync(plc, _op115StringMap["产品名称"].Addr, _op115StringMap["产品名称"].Len) }
};
var intTasks = new Dictionary<string, Task<int>>
{
{ "运行状态", ReadPlcIntAsync(plc, _op115IntMap["运行状态"]) },
{ "设备模式", ReadPlcIntAsync(plc, _op115IntMap["设备模式"]) },
{ "设备在线状态", ReadPlcIntAsync(plc, _op115IntMap["设备在线状态"]) },
{ "生产模式", ReadPlcIntAsync(plc, _op115IntMap["生产模式"]) }
};
// 2. 并行等待所有任务完成
var allTasks = new List<Task>();
allTasks.AddRange(stringTasks.Values);
allTasks.AddRange(intTasks.Values);
await Task.WhenAll(allTasks).ConfigureAwait(false);
// 3. 提取结果
var now = DateTime.Now;
var productModel = stringTasks["产品型号"].Result ?? string.Empty;
var productName = stringTasks["产品名称"].Result ?? string.Empty;
var runStatus = intTasks["运行状态"].Result;
var machineModel = intTasks["设备模式"].Result;
var onlineStatus = intTasks["设备在线状态"].Result;
var produceModel = intTasks["生产模式"].Result;
// 4. 业务逻辑转换
var reworkFlag = produceModel == 2 ? "1" : "0";
var produceModelDesc = produceModel switch
{
1 => "点检模式",
2 => "返工模式",
4 => "样件模式",
5 => "正常模式",
_ => produceModel.ToString()
};
var onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线";
var qualificationFlag = "1"; // 上下料工位默认合格
// 5. 构建完整实体
return new PlcProductionData
{
// 基础字段
PlcIp = ip,
OccurTime = now,
LineCode = "line2",
WorkstationCode = workstationCode,
WorkstationName = "自动上下料到固化炉工位",
ProductModel = productModel,
ProductName = productName,
ReworkFlag = reworkFlag,
Automanual = machineModel,
Runstatus = runStatus,
OnlineStatus = onlineStatusDesc,
ProduceModel = produceModelDesc,
QualificationFlag = qualificationFlag,
CreatedBy = "PLC",
CreatedTime = now,
};
}
catch (Exception ex)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] OP115读取异常{ex.Message}");
return null;
}
}
/// <summary>
/// 读取OP140数据气密性测试工位DB1001
/// </summary>
public async Task<PlcProductionData> ReadOP140DataAsync(Plc plc, string ip, string workstationCode)
{
// 前置校验:快速失败
if (plc == null || !plc.IsConnected) return null;
if (string.IsNullOrWhiteSpace(ip) || string.IsNullOrWhiteSpace(workstationCode))
throw new ArgumentNullException("IP或工位编码不能为空");
try
{
// 1. 批量创建并行读取任务
var stringTasks = new Dictionary<string, Task<string>>
{
{ "产品型号", ReadPlcStringAsync(plc, _op140StringMap["产品型号"].Addr, _op140StringMap["产品型号"].Len) },
{ "产品名称", ReadPlcStringAsync(plc, _op140StringMap["产品名称"].Addr, _op140StringMap["产品名称"].Len) },
{ "查询SN", ReadPlcStringAsync(plc, _op140StringMap["查询SN"].Addr, _op140StringMap["查询SN"].Len) }
};
var intTasks = new Dictionary<string, Task<int>>
{
{ "运行状态", ReadPlcIntAsync(plc, _op140IntMap["运行状态"]) },
{ "设备模式", ReadPlcIntAsync(plc, _op140IntMap["设备模式"]) },
{ "设备在线状态", ReadPlcIntAsync(plc, _op140IntMap["设备在线状态"]) },
{ "生产模式", ReadPlcIntAsync(plc, _op140IntMap["生产模式"]) },
{ "实际产量", ReadPlcIntAsync(plc, _op140IntMap["实际产量"]) },
{ "产品结果", ReadPlcIntAsync(plc, _op140IntMap["产品结果"]) },
{ "Socket", ReadPlcIntAsync(plc, _op140IntMap["Socket"]) },
{ "托盘号", ReadPlcIntAsync(plc, _op140IntMap["托盘号"]) }
};
var realTasks = new Dictionary<string, Task<float>>
{
{ "压力值", ReadPlcRealAsync(plc, _op140IntMap["压力值"]) },
{ "泄露值", ReadPlcRealAsync(plc, _op140IntMap["泄露值"]) },
{ "节拍时间", ReadPlcRealAsync(plc, _op140IntMap["节拍时间"]) }
};
// 2. 并行等待所有任务完成
var allTasks = new List<Task>();
allTasks.AddRange(stringTasks.Values);
allTasks.AddRange(intTasks.Values);
allTasks.AddRange(realTasks.Values);
await Task.WhenAll(allTasks).ConfigureAwait(false);
// 3. 提取结果
var now = DateTime.Now;
var productModel = stringTasks["产品型号"].Result ?? string.Empty;
var productName = stringTasks["产品名称"].Result ?? string.Empty;
var sn1 = stringTasks["查询SN"].Result ?? string.Empty;
var runStatus = intTasks["运行状态"].Result;
var machineModel = intTasks["设备模式"].Result;
var onlineStatus = intTasks["设备在线状态"].Result;
var produceModel = intTasks["生产模式"].Result;
var actualOutput = intTasks["实际产量"].Result;
var productResult = intTasks["产品结果"].Result;
var socket = intTasks["Socket"].Result;
var trayNo = intTasks["托盘号"].Result.ToString();
var pressure = realTasks["压力值"].Result;
var leak = realTasks["泄露值"].Result;
var cycleTime = realTasks["节拍时间"].Result;
// 4. 业务逻辑转换
var reworkFlag = produceModel == 2 ? "1" : "0";
var produceModelDesc = produceModel switch
{
1 => "点检模式",
2 => "返工模式",
4 => "样件模式",
5 => "正常模式",
_ => produceModel.ToString()
};
var onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线";
var qualificationFlag = productResult == 1 ? "1" : "2";
// 5. 构建完整实体
return new PlcProductionData
{
// 基础字段
PlcIp = ip,
OccurTime = now,
LineCode = "line2",
WorkstationCode = workstationCode,
WorkstationName = "气密性测试工位",
ProductModel = productModel,
ProductName = productName,
ProductCode = sn1,
SN1 = sn1,
TrayNo = trayNo,
ReworkFlag = reworkFlag,
Automanual = machineModel,
Runstatus = runStatus,
OnlineStatus = onlineStatusDesc,
ProduceModel = produceModelDesc,
QualificationFlag = qualificationFlag,
ProductionCycle = (int)Math.Round(cycleTime),
CreatedBy = "PLC",
CreatedTime = now,
// 测试参数
PinPressure1 = pressure.ToString("F2"),
PinPressure2 = leak.ToString("F2"),
};
}
catch (Exception ex)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] OP140读取异常{ex.Message}");
return null;
}
}
/// <summary>
/// 读取OP165数据自动贴标工位DB1001
/// </summary>
public async Task<PlcProductionData> ReadOP165DataAsync(Plc plc, string ip, string workstationCode)
{
// 前置校验:快速失败
if (plc == null || !plc.IsConnected) return null;
if (string.IsNullOrWhiteSpace(ip) || string.IsNullOrWhiteSpace(workstationCode))
throw new ArgumentNullException("IP或工位编码不能为空");
try
{
// 1. 批量创建并行读取任务
var stringTasks = new Dictionary<string, Task<string>>
{
{ "产品型号", ReadPlcStringAsync(plc, _op165StringMap["产品型号"].Addr, _op165StringMap["产品型号"].Len) },
{ "产品名称", ReadPlcStringAsync(plc, _op165StringMap["产品名称"].Addr, _op165StringMap["产品名称"].Len) },
{ "查询SN", ReadPlcStringAsync(plc, _op165StringMap["查询SN"].Addr, _op165StringMap["查询SN"].Len) },
{ "结果SN", ReadPlcStringAsync(plc, _op165StringMap["结果SN"].Addr, _op165StringMap["结果SN"].Len) },
{ "二维码内容", ReadPlcStringAsync(plc, _op165StringMap["二维码内容"].Addr, _op165StringMap["二维码内容"].Len) },
{ "下料工位条码", ReadPlcStringAsync(plc, _op165StringMap["下料工位条码"].Addr, _op165StringMap["下料工位条码"].Len) }
};
var intTasks = new Dictionary<string, Task<int>>
{
{ "运行状态", ReadPlcIntAsync(plc, _op165IntMap["运行状态"]) },
{ "设备模式", ReadPlcIntAsync(plc, _op165IntMap["设备模式"]) },
{ "设备在线状态", ReadPlcIntAsync(plc, _op165IntMap["设备在线状态"]) },
{ "生产模式", ReadPlcIntAsync(plc, _op165IntMap["生产模式"]) },
{ "实际产量", ReadPlcIntAsync(plc, _op165IntMap["实际产量"]) },
{ "产品总结果", ReadPlcIntAsync(plc, _op165IntMap["产品总结果"]) },
{ "轴承检测结果", ReadPlcIntAsync(plc, _op165IntMap["轴承检测结果"]) },
{ "贴标拍照结果", ReadPlcIntAsync(plc, _op165IntMap["贴标拍照结果"]) },
{ "托盘号", ReadPlcIntAsync(plc, _op165IntMap["托盘号"]) }
};
var realTasks = new Dictionary<string, Task<float>>
{
{ "节拍时间", ReadPlcRealAsync(plc, _op165IntMap["节拍时间"]) }
};
// 2. 并行等待所有任务完成
var allTasks = new List<Task>();
allTasks.AddRange(stringTasks.Values);
allTasks.AddRange(intTasks.Values);
allTasks.AddRange(realTasks.Values);
await Task.WhenAll(allTasks).ConfigureAwait(false);
// 3. 提取结果
var now = DateTime.Now;
var productModel = stringTasks["产品型号"].Result ?? string.Empty;
var productName = stringTasks["产品名称"].Result ?? string.Empty;
var sn1 = stringTasks["查询SN"].Result ?? string.Empty;
var sn2 = stringTasks["结果SN"].Result ?? string.Empty;
var qrCode = stringTasks["二维码内容"].Result ?? string.Empty;
var outFeedBarcode = stringTasks["下料工位条码"].Result ?? string.Empty;
var runStatus = intTasks["运行状态"].Result;
var machineModel = intTasks["设备模式"].Result;
var onlineStatus = intTasks["设备在线状态"].Result;
var produceModel = intTasks["生产模式"].Result;
var actualOutput = intTasks["实际产量"].Result;
var productTotalResult = intTasks["产品总结果"].Result;
var bearingResult = intTasks["轴承检测结果"].Result;
var labelPhotoResult = intTasks["贴标拍照结果"].Result;
var trayNo = intTasks["托盘号"].Result.ToString();
var cycleTime = realTasks["节拍时间"].Result;
// 4. 业务逻辑转换
var reworkFlag = produceModel == 2 ? "1" : "0";
var produceModelDesc = produceModel switch
{
1 => "点检模式",
2 => "返工模式",
4 => "样件模式",
5 => "正常模式",
_ => produceModel.ToString()
};
var onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线";
var qualificationFlag = productTotalResult == 1 ? "1" : "2";
// 6. 构建完整实体
return new PlcProductionData
{
// 基础字段
PlcIp = ip,
OccurTime = now,
LineCode = "line2",
WorkstationCode = workstationCode,
WorkstationName = "自动贴标工位",
ProductModel = productModel,
ProductName = productName,
ProductCode = sn1,
SN1 = sn1,
SN2 = sn2,
TrayNo = trayNo,
ReworkFlag = reworkFlag,
Automanual = machineModel,
Runstatus = runStatus,
OnlineStatus = onlineStatusDesc,
ProduceModel = produceModelDesc,
QualificationFlag = qualificationFlag,
ProductionCycle = (int)Math.Round(cycleTime),
CreatedBy = "PLC",
CreatedTime = now,
CameraResult = labelPhotoResult == 1 ? "1" : "2", // 贴标拍照结果映射
};
}
catch (Exception ex)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] OP165读取异常{ex.Message}");
return null;
}
}
#endregion
// 可选:添加连接池清理方法(防止长期运行导致连接泄露)
private void CleanupExpiredConnections()
{
var expiredTime = DateTime.Now.AddMinutes(-5); // 5分钟未使用的连接清理
// 先复制所有Key到列表避免遍历中修改原集合
var allKeys = _plcConnPool.Keys.ToList();
foreach (var key in allKeys)
{
if (!_plcConnPool.TryGetValue(key, out var poolItem))
continue;
if (poolItem.LastUsedTime < expiredTime)
{
if (_plcConnPool.TryRemove(key, out var removedItem))
{
try
{
if (removedItem.Client != null && removedItem.Client.IsConnected)
removedItem.Client.Close();
if (removedItem.Client is IDisposable disposable)
disposable.Dispose();
// 可选置空引用帮助GC回收
removedItem.Client = null;
}
catch
{
// 静默释放,避免清理失败影响主流程
}
}
}
}
}
// 在类的构造函数中启动定时清理(可选)
// public PlcService(IOptions<GlobalPlcConfig> globalConfig)
// {
// _globalConfig = globalConfig?.Value ?? throw new ArgumentNullException(nameof(globalConfig));
// _plcConfigs = initPlcConfigs(_plcConfigs);
// // 每30秒清理一次过期连接
// new Timer(_ => CleanupExpiredConnections(), null, TimeSpan.Zero, TimeSpan.FromSeconds(30));
// }
/// <summary>
/// 测试单个PLC的连接、读、写功能
/// </summary>
/// <param name="config">单个PLC的配置参数</param>
/// <param name="cancellationToken">取消令牌</param>
/// <returns>测试结果</returns>
public async Task<PlcTestResult> TestSinglePlcAsync(PlcConfig config, CancellationToken cancellationToken = default)
{
// 1. 极简参数校验(提前返回,减少嵌套)
if (config == null)
throw new ArgumentNullException(nameof(config), "PLC测试配置不能为空");
if (string.IsNullOrWhiteSpace(config.Ip))
return new PlcTestResult { PlcName = config.PlcName, Ip = config.Ip, ConnectSuccess = false, ConnectMessage = "IP地址为空" };
var result = new PlcTestResult { PlcName = config.PlcName, Ip = config.Ip };
Plc plc = null;
try
{
// 2. 初始化PLC客户端
plc = CreatePlcClient(CpuType.S71500, config.Ip, config.Rack, config.Slot);
// 3. 带超时的连接测试(精简逻辑)
var connectTask = OpenPlcConnectionAsync(plc);
if (await Task.WhenAny(connectTask, Task.Delay(_globalConfig.ReadWriteTimeout, cancellationToken)) != connectTask)
{
result.ConnectSuccess = false;
result.ConnectMessage = $"连接超时({_globalConfig.ReadWriteTimeout}ms";
return result;
}
await connectTask;
// 4. 连接状态校验(精简分支)
if (!plc.IsConnected)
{
result.ConnectSuccess = false;
result.ConnectMessage = "连接失败PLC未返回连接状态";
return result;
}
result.ConnectSuccess = true;
result.ConnectMessage = "连接成功";
const string TestAddress = "DB1010.DBB238";
if (!string.IsNullOrWhiteSpace(TestAddress))
{
// 读取测试
try
{
var readValue = await Task.Run(() => plc.Read(TestAddress), cancellationToken);
result.ReadSuccess = true;
result.ReadValue = FormatPlcValue(readValue);
result.ReadMessage = "通用地址读取成功";
}
catch (Exception ex)
{
result.ReadSuccess = false;
result.ReadMessage = $"通用地址读取失败:{ex.Message}";
}
// 写入测试
try
{
bool writeOk = await Task.Run(() => WritePlcValue(plc, TestAddress, "1"), cancellationToken);
result.WriteSuccess = writeOk;
result.WriteMessage = writeOk ? "写入成功" : "写入失败(值类型与地址不匹配)";
}
catch (Exception ex)
{
result.WriteSuccess = false;
result.WriteMessage = $"写入失败:{ex.Message}";
}
}
}
catch (OperationCanceledException)
{
result.ConnectSuccess = false;
result.ConnectMessage = "测试被取消";
}
catch (Exception ex)
{
result.ConnectSuccess = false;
result.ConnectMessage = $"连接异常:{ex.Message}";
}
finally
{
ReleasePlcConnection(plc);
}
return result;
}
/// <summary>
/// 批量测试配置文件中所有PLC的读写功能
/// </summary>
/// <param name="cancellationToken">取消令牌</param>
/// <returns>所有PLC的测试结果列表</returns>
public async Task<List<PlcTestResult>> BatchTestAllPlcAsync(CancellationToken cancellationToken = default)
{
if (_plcConfigs == null || _plcConfigs.Count == 0)
throw new InvalidOperationException("未从配置文件加载到任何PLC参数请检查PlcConfigs配置");
// 并行测试所有PLC带最大并行度限制避免资源耗尽
var testTasks = _plcConfigs
.Select(config => TestSinglePlcAsync(config, cancellationToken))
.ToList();
var results = await Task.WhenAll(testTasks);
return results.ToList();
}
/// <summary>
/// 单独读取指定PLC的某个地址数据
/// </summary>
/// <param name="ip">PLC的IP地址</param>
/// <param name="rack">机架号</param>
/// <param name="slot">槽位号</param>
/// <param name="address">读取地址如DB1.DBD0</param>
/// <param name="cpuType">PLC型号</param>
/// <returns>读取结果(成功状态、值、消息)</returns>
public async Task<(bool Success, string Value, string Message)> ReadPlcDataAsync(
string ip,
short rack,
short slot,
string address,
CpuType cpuType = CpuType.S71500)
{
// 参数校验
if (string.IsNullOrWhiteSpace(ip))
return (false, "", "PLC IP地址不能为空");
if (string.IsNullOrWhiteSpace(address))
return (false, "", "读取地址不能为空");
Plc plc = null;
try
{
plc = CreatePlcClient(cpuType, ip, rack, slot);
await OpenPlcConnectionAsync(plc);
if (!plc.IsConnected)
return (false, "", "PLC连接失败请检查IP/机架号/槽位号是否正确");
var value = await Task.Run(() => plc.Read(address));
return (true, FormatPlcValue(value), "读取成功");
}
catch (Exception ex)
{
return (false, "", $"读取失败:{ex.Message}");
}
finally
{
ReleasePlcConnection(plc);
}
}
/// <summary>
/// 单独写入数据到指定PLC的某个地址
/// </summary>
/// <param name="ip">PLC的IP地址</param>
/// <param name="rack">机架号</param>
/// <param name="slot">槽位号</param>
/// <param name="address">写入地址如DB1.DBD0</param>
/// <param name="valueStr">写入的值(字符串格式)</param>
/// <param name="cpuType">PLC型号</param>
/// <returns>写入结果(成功状态、消息)</returns>
public async Task<(bool Success, string Message)> WritePlcDataAsync(
string ip,
short rack,
short slot,
string address,
string valueStr,
CpuType cpuType = CpuType.S71500)
{
// 参数校验
if (string.IsNullOrWhiteSpace(ip))
return (false, "PLC IP地址不能为空");
if (string.IsNullOrWhiteSpace(address))
return (false, "写入地址不能为空");
if (valueStr == null) // 允许空字符串(如清空值)
return (false, "写入值不能为null");
Plc plc = null;
try
{
plc = CreatePlcClient(cpuType, ip, rack, slot);
await OpenPlcConnectionAsync(plc);
if (!plc.IsConnected)
return (false, "PLC连接失败请检查IP/机架号/槽位号是否正确");
bool writeOk = await Task.Run(() => WritePlcValue(plc, address, valueStr));
return (writeOk, writeOk ? "写入成功" : "写入失败(值类型与地址不匹配)");
}
catch (Exception ex)
{
return (false, $"写入失败:{ex.Message}");
}
finally
{
ReleasePlcConnection(plc);
}
}
#endregion
#region
/// <summary>
/// 创建PLC客户端实例统一配置超时
/// </summary>
private Plc CreatePlcClient(CpuType cpuType, string ip, short rack, short slot)
{
var plc = new Plc(cpuType, ip, rack, slot)
{
ReadTimeout = _globalConfig.ReadWriteTimeout,
WriteTimeout = _globalConfig.ReadWriteTimeout
};
return plc;
}
/// <summary>
/// 异步打开PLC连接封装同步方法为异步
/// </summary>
// 优化后的OpenPlcConnectionAsync
private async Task<bool> OpenPlcConnectionAsync(Plc plc)
{
if (plc == null) return false;
try
{
// 带超时的连接操作
var openTask = Task.Run(() => plc.Open());
if (await Task.WhenAny(openTask, Task.Delay(_globalConfig.ReadWriteTimeout)) != openTask)
{
return false;
}
await openTask;
return plc.IsConnected;
}
catch
{
return false;
}
}
/// <summary>
/// 释放PLC连接安全关闭+资源释放)
/// </summary>
private void ReleasePlcConnection(Plc plc)
{
if (plc == null) return;
try
{
if (plc.IsConnected)
plc.Close();
// 正确释放PLC实例适配S7.Net显式实现IDisposable
if (plc is IDisposable disposable)
disposable.Dispose();
}
catch (Exception ex)
{
Console.WriteLine($"PLC连接关闭失败{ex.Message}");
}
// 移除finally中的Dispose(),避免误释放服务
}
/// <summary>
/// 按业务规则解析PLC字符串支持中文GBK编码
/// </summary>
private async Task<string> ReadPlcStringAsync(Plc plc, string addr, int maxLen)
{
try
{
// 解析地址DB1010.DBB50 → DB编号1010 + 起始字节50
var parts = addr.Split('.', StringSplitOptions.RemoveEmptyEntries);
if (parts.Length != 2)
return string.Empty;
if (!int.TryParse(parts[0].Replace("DB", ""), out int dbNum) || dbNum <= 0)
return string.Empty;
if (!int.TryParse(parts[1].Replace("DBB", ""), out int startByte) || startByte < 0)
return string.Empty;
// 读取字节数组
var bytes = await Task.Run(() => plc.ReadBytes(DataType.DataBlock, dbNum, startByte, maxLen));
if (bytes == null || bytes.Length < 3)
return string.Empty;
// 严格按规则解析bytes[0]=总长度(备用)、bytes[1]=有效长度、bytes[2+]=内容
int validLen = Math.Clamp(bytes[1], 0, bytes.Length - 2);
if (validLen <= 0)
return string.Empty;
// 提取有效内容并转字符串GBK编码支持中文
var contentBytes = new byte[validLen];
Array.Copy(bytes, 2, contentBytes, 0, validLen);
return Encoding.GetEncoding("GBK").GetString(contentBytes).Trim('\0', ' ', '\t');
}
catch
{
return string.Empty;
}
}
/// </summary>
/// <param name="plc">PLC客户端实例</param>
/// <param name="addr">读取地址如DB1010.DBW226</param>
/// <returns>解析后的整数值读取失败返回0</returns>
private async Task<int> ReadPlcIntAsync(Plc plc, string addr)
{
if (plc == null)
{
return 0;
}
if (string.IsNullOrWhiteSpace(addr))
{
return 0;
}
try
{
var val = await plc.ReadAsync(addr).ConfigureAwait(false);
return val switch
{
short s => s, // 16位短整型DBW默认类型
int i => i, // 32位整型兼容返回
uint ui => (int)ui, // 无符号32位整型
byte b => b, // 8位字节型
ushort us => us, // 无符号16位整型
long l => (int)l, // 64位整型截断为32位
ulong ul => (int)ul, // 无符号64位整型截断为32位
float f => (int)f, // 浮点数转整型兼容PLC数值存储
double d => (int)d, // 双精度浮点数转整型
_ => 0 // 未知类型返回0
};
}
catch (Exception ex)
{
return 0;
}
}
private async Task<int> ReadPlcDIntAsync(Plc plc, string addr)
{
if (plc == null || string.IsNullOrWhiteSpace(addr))
{
Console.WriteLine($"DInt读取失败参数无效地址{addr}");
return 0;
}
try
{
var val = await Task.Run(() => plc.Read(addr));
Console.WriteLine($"DInt地址[{addr}] 原始值:{val},类型:{val?.GetType().Name}");
return val switch
{
int i => i,
long l => (int)l,
uint ui => (int)ui,
ulong ul => (int)ul,
_ => 0
};
}
catch (Exception ex)
{
Console.WriteLine($"DInt读取失败地址{addr}{ex.Message}");
return 0;
}
}
private async Task<float> ReadPlcRealAsync(Plc plc, string addr)
{
// 前置校验:快速过滤无效入参
if (plc is null || !plc.IsConnected || string.IsNullOrWhiteSpace(addr))
return 0.0f;
try
{
// 地址解析仅支持DBx.DBDy格式增加容错
var parts = addr.Split('.');
if (parts.Length != 2 || !parts[0].StartsWith("DB") || !parts[1].StartsWith("DBD"))
return 0.0f;
if (!int.TryParse(parts[0].Substring(2), out int dbNumber) ||
!int.TryParse(parts[1].Substring(3), out int startByte))
return 0.0f;
// 核心读取调用PLC非泛型读取方法
var result = await plc.ReadAsync(
DataType.DataBlock,
dbNumber,
startByte,
VarType.Real,
1).ConfigureAwait(false);
// 关键修复:直接处理单个数值(非数组)
if (result != null)
{
// 不管result是int/double/float都强制转为float
return Convert.ToSingle(result);
}
// 无有效结果返回0
return 0.0f;
}
catch
{
// 异常兜底返回0
return 0.0f;
}
}
/// <summary>
/// 格式化PLC读取的值转为友好的字符串
/// </summary>
private string FormatPlcValue(object value)
{
if (value == null) return "空值";
return value switch
{
float f => f.ToString("0.000"), // 浮点数保留3位小数
double d => d.ToString("0.000"), // 补充双精度浮点数支持
short s => s.ToString(), // 16位整数
byte b => b.ToString(), // 8位整数
bool b => b.ToString(), // 布尔值
int i => i.ToString(), // 32位整数
uint ui => ui.ToString(), // 无符号32位整数
long l => l.ToString(), // 64位整数
ulong ul => ul.ToString(), // 无符号64位整数
_ => value.ToString() // 其他类型直接转字符串
};
}
/// <summary>
/// 根据地址类型转换值并写入PLC
/// </summary>
private bool WritePlcValue(Plc plc, string address, string valueStr)
{
// 双字DBD/DD浮点数或32位整数
if (address.Contains("DBD") || address.Contains("DD"))
{
if (float.TryParse(valueStr, out float f))
{
plc.Write(address, f);
return true;
}
else if (int.TryParse(valueStr, out int i))
{
plc.Write(address, i);
return true;
}
}
// 字DBW/DW16位整数
else if (address.Contains("DBW") || address.Contains("DW"))
{
if (short.TryParse(valueStr, out short s))
{
plc.Write(address, s);
return true;
}
}
// 字节DBB/DB8位整数
else if (address.Contains("DBB") || address.Contains("DB"))
{
if (byte.TryParse(valueStr, out byte b))
{
plc.Write(address, b);
return true;
}
}
// 位DBX布尔值兼容0/1输入
else if (address.Contains("DBX"))
{
if (bool.TryParse(valueStr, out bool bl))
{
plc.Write(address, bl);
return true;
}
else if (valueStr == "0")
{
plc.Write(address, false);
return true;
}
else if (valueStr == "1")
{
plc.Write(address, true);
return true;
}
}
// 不匹配的类型
return false;
}
#endregion
#region
/// <summary>
/// 实现IDisposable接口释放资源
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this); // 通知GC无需调用终结器
}
/// <summary>
/// 实际释放资源的逻辑(区分托管/非托管资源)
/// </summary>
/// <param name="disposing">是否释放托管资源</param>
protected virtual void Dispose(bool disposing)
{
if (_disposed) return; // 避免重复释放
// 释放托管资源
if (disposing)
{
// 此处无长期持有的PLC连接若有可在此统一释放
}
// 标记为已释放
_disposed = true;
}
/// <summary>
/// 终结器防忘记手动Dispose
/// </summary>
~PlcService()
{
Dispose(false);
}
#endregion
private List<PlcConfig> initPlcConfigs(List<PlcConfig> result)
{
var defaultResult = result ?? new List<PlcConfig>();
try
{
List<PlcConfig> query = _plantWorkstationService.Queryable()
.Where(it => it.Status == 1)
.Select(it => new PlcConfig
{
PlcName = it.WorkstationCode,
Ip = it.PlcIP,
Rack = (short)it.Rack, // 直接强制转换it.Rack是int非空
Slot = (short)it.Slot // 同理it.Slot是int非空
})
.ToList();
return query.Count > 0 ? query : defaultResult;
}
catch (Exception ex)
{
Console.WriteLine($"初始化PLC配置异常{ex.Message}");
return defaultResult;
}
}
// 提取写PLC返回值的通用方法统一处理逻辑和日志
private void WritePlcSaveRequestResult(Plc plc, string ip, string plcName, PlcProductionData prodData, string saveResult)
{
try
{
if (plcName == "OP058")
{
WritePlcValue(plc, _mesop058IntReturnMap["设备使能"], "1");
//WritePlcValue(plc, _mesIntReturnMap["工位开始查询结果"], "1");
WritePlcValue(plc, _mesop058IntReturnMap["保存结果"], saveResult);
if (prodData.ProductModel != null && prodData.ProductModel.Length > 0)
{
WritePlcString(plc, _mesop058StringReturnMap["产品型号"].Addr, _mesop058StringReturnMap["产品型号"].Len, prodData.ProductModel);
}
else
{
WritePlcString(plc, _mesop058StringReturnMap["产品型号"].Addr, _mesop058StringReturnMap["产品型号"].Len, prodData.ProductModel);
}
WritePlcString(plc, _mesop058StringReturnMap["订单下发"].Addr, _mesop058StringReturnMap["订单下发"].Len, "cpxhtest");
}
else
{
WritePlcValue(plc, _mesIntReturnMap["设备使能"], "1");
//WritePlcValue(plc, _mesIntReturnMap["工位开始查询结果"], "1");
WritePlcValue(plc, _mesIntReturnMap["保存结果"], saveResult);
if (prodData.ProductModel != null && prodData.ProductModel.Length > 0)
{
WritePlcString(plc, _mesStringReturnMap["产品型号"].Addr, _mesStringReturnMap["产品型号"].Len, prodData.ProductModel);
}
else
{
WritePlcString(plc, _mesStringReturnMap["产品型号"].Addr, _mesStringReturnMap["产品型号"].Len, prodData.ProductModel);
}
WritePlcString(plc, _mesStringReturnMap["订单下发"].Addr, _mesStringReturnMap["订单下发"].Len, "cpxhtest");
}
}
catch (Exception ex)
{
}
}
/// <summary>
/// 记录PLC过站状态
/// </summary>
private async Task RecordPlcOperationResult(string plcName, PlcProductionData prodData)
{
// 1. 入参校验(极致精简,减少分支和字符串操作)
if (string.IsNullOrWhiteSpace(plcName))
throw new ArgumentNullException(nameof(plcName), "PLC/工位名称不能为空");
if (prodData is null)
throw new ArgumentNullException(nameof(prodData), "PLC生产数据实体不能为空");
// 2. SN校验直接判断减少临时变量赋值
if (string.IsNullOrWhiteSpace(prodData.SN2?.Trim()))
return;
var strSN = prodData.SN2.Trim(); // 仅在非空时赋值,减少内存分配
// 3. 合格状态转换(提前计算,减少后续引用开销)
var result = string.Equals(prodData.QualificationFlag, "1", StringComparison.OrdinalIgnoreCase) ? 1 : 0;
var now = DateTime.Now;
try
{
// 在方法内创建上下文并使用using确保自动释放
using var context = DbScoped.SugarScope.CopyNew();
if (context == null)
throw new InvalidOperationException("无法创建数据库上下文请检查SqlSugar配置");
var routingCode = string.Empty;
try
{
routingCode = await context.Queryable<ProcessRouting>()
.LeftJoin<ProcessOperation>((r, o) => r.RoutingCode == o.FkRoutingCode)
.Where((r, o) => r.FkProductMaterialCode == strSN && r.Status == 1)
.Select((r, o) => o.FkRoutingCode)
.FirstAsync(); // 直接取第一条避免ToList+First的双重开销
}
catch
{
}
// 5. 返工状态判断(无分配判断,直接赋值)
var productionLifeStage = string.Equals(prodData.ReworkFlag, "1", StringComparison.OrdinalIgnoreCase) ? 2 : 1;
// 6. 构建记录(结构体思维,减少冗余字段)
var askOutStation = new ProductPassStationRecord
{
ProductSN = strSN,
WorkstationCode = plcName,
Routingcode = routingCode,
OperationCode = plcName,
ProductionLifeStage = productionLifeStage,
PasstationType = 1,
ResultCode = result,
EffectTime = now,
CreatedTime = now
};
// 7. 插入数据库批量插入优化减少IO交互
var insertCount = await context.Insertable(askOutStation).ExecuteCommandAsync();
}
catch (ArgumentNullException ex)
{
Console.WriteLine($"[{now:HH:mm:ss}] {plcName} - 入参异常:{ex.Message}");
throw;
}
catch (Exception ex)
{
Console.WriteLine($"[{now:HH:mm:ss}] {plcName} - {strSN} 记录异常:{ex.Message}");
}
}
/// <summary>
/// 异步复位上传请求(独立方法,非阻塞)
/// </summary>
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}");
}
}
/// <summary>
/// 异步复位保存请求(独立方法,非阻塞)
/// </summary>
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}");
}
}
/// <summary>
/// 向PLC写入字符串字节数组形式
/// </summary>
/// <param name="plc">PLC客户端</param>
/// <param name="startAddress">字符串起始地址如DB1101.DBB1016</param>
/// <param name="strLength">PLC定义的字符串长度如14</param>
/// <param name="value">要写入的字符串</param>
private void WritePlcString(Plc plc, string startAddress, int strLength, string value)
{
// 1. 解析起始地址提取DB块、起始字节
if (!ParsePlcAddress(startAddress, out var dataType, out int dbNumber, out int startByte))
{
throw new ArgumentException($"无效的PLC字符串起始地址{startAddress}");
}
// 2. 处理字符串转字节数组长度不足补0超长截断
byte[] strBytes = Encoding.ASCII.GetBytes(value ?? "");
byte[] plcBytes = new byte[strLength]; // PLC字符串固定长度
// 复制字符串字节,超长则截断
int copyLength = Math.Min(strBytes.Length, strLength);
Array.Copy(strBytes, 0, plcBytes, 0, copyLength);
// 剩余字节填充0清空原有内容
if (copyLength < strLength)
{
Array.Clear(plcBytes, copyLength, strLength - copyLength);
}
// 3. 写入PLC批量写入字节数组
plc.WriteBytes(dataType, dbNumber, startByte, plcBytes);
}
/// </summary>
/// <param name="address">PLC地址如DB1101.DBB1016</param>
/// <param name="dataType">数据类型DB/Input等</param>
/// <param name="dbNumber">DB块编号如1101</param>
/// <param name="startByte">起始字节如1016</param>
/// <returns>是否解析成功</returns>
private bool ParsePlcAddress(string address, out DataType dataType, out int dbNumber, out int startByte)
{
dataType = DataType.DataBlock; // 默认DB块
dbNumber = 0;
startByte = 0;
try
{
// 匹配格式DB1101.DBB1016
var match = System.Text.RegularExpressions.Regex.Match(address, @"DB(\d+)\.DBB(\d+)");
if (match.Success)
{
dbNumber = int.Parse(match.Groups[1].Value);
startByte = int.Parse(match.Groups[2].Value);
return true;
}
return false;
}
catch (Exception ex)
{
return false;
}
}
}
}