diff --git a/RIZO.Admin.WebApi/PLC/Model/PlcProductionData.cs b/RIZO.Admin.WebApi/PLC/Model/PlcProductionData.cs
index 4e1d870..6e84fc7 100644
--- a/RIZO.Admin.WebApi/PLC/Model/PlcProductionData.cs
+++ b/RIZO.Admin.WebApi/PLC/Model/PlcProductionData.cs
@@ -420,7 +420,7 @@ namespace RIZO.Admin.WebApi.PLC.Model
///
/// 芯片 SN(PWM 条码)
///
- [SugarColumn(ColumnName = "Screw7TightenTime")]
+ [SugarColumn(ColumnName = "ChipSN")]
public string ChipSN { get; set; }
///
diff --git a/RIZO.Admin.WebApi/PLC/Service/PlcHostedService.cs b/RIZO.Admin.WebApi/PLC/Service/PlcHostedService.cs
index 9b96d96..a4953d2 100644
--- a/RIZO.Admin.WebApi/PLC/Service/PlcHostedService.cs
+++ b/RIZO.Admin.WebApi/PLC/Service/PlcHostedService.cs
@@ -123,7 +123,6 @@ namespace RIZO.Admin.WebApi.PLC.Service
Rack = (short)it.Rack, // 空值兜底
Slot = (short)it.Slot // 空值兜底
})
- .Where(c => !string.IsNullOrWhiteSpace(c.Ip))
.ToList();
}
catch (Exception ex)
diff --git a/RIZO.Admin.WebApi/PLC/Service/PlcService.cs b/RIZO.Admin.WebApi/PLC/Service/PlcService.cs
index dc5ad46..341a0f7 100644
--- a/RIZO.Admin.WebApi/PLC/Service/PlcService.cs
+++ b/RIZO.Admin.WebApi/PLC/Service/PlcService.cs
@@ -32,6 +32,7 @@ namespace RIZO.Admin.WebApi.PLC.Service
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)
@@ -41,15 +42,15 @@ namespace RIZO.Admin.WebApi.PLC.Service
//MES返回PLC请求映射
private readonly Dictionary _mesIntReturnMap = new()
{
- { "设备使能", "DB1050.DBW0" }, // Int
- { "工位开始查询结果", "DB1050.DBW2000" }, // Int
- { "保存结果", "DB1050.DBW2002" }, // Int
+ { "设备使能", "DB1101.DBW0" }, // Int
+ { "工位开始查询结果", "DB1101.DBW2000" }, // Int
+ { "保存结果", "DB1101.DBW2002" }, // Int
};
private readonly Dictionary _mesStringReturnMap = new()
{
- { "产品型号", ("DB1001.DBB1016", 14) }, // String[14]
- { "订单下发", ("DB1001.DBB1032", 50) }, // String[50]
+ { "产品型号", ("DB1101.DBB1016", 14) }, // String[14]
+ { "订单下发", ("DB1101.DBB1032", 50) }, // String[50]
};
// OP020-2 专属地址映射(合盖工位,DB1001)
@@ -403,17 +404,9 @@ namespace RIZO.Admin.WebApi.PLC.Service
else
{
plc = CreatePlcClient(cpuType, ip, rack, slot);
- try
- {
- await OpenPlcConnectionAsync(plc);
- if (!plc.IsConnected) return (false, null, $"{plcName}连接失败(含2次重试)");
- _plcConnPool.TryAdd(poolKey, (plc, DateTime.Now));
- }
- catch
- {
- ReleasePlcConnection(plc);
- return (false, null, $"{plcName}连接失败(含2次重试)");
- }
+ await OpenPlcConnectionAsync(plc);
+ if (!plc.IsConnected) return (false, null, $"{plcName}连接失败");
+ _plcConnPool.TryAdd(poolKey, (plc, DateTime.Now));
}
// 4. 多工位请求状态读取(精简分支,保留原逻辑,移除冗余注释)
@@ -508,13 +501,12 @@ namespace RIZO.Admin.WebApi.PLC.Service
? $"{plcName}生产数据读取成功(复用连接)"
: $"{plcName}生产数据读取成功(新建连接)";
WritePlcSaveRequestResult(plc, ip, plcName, prodData, "1");
-
+ //保存成功,到PLC过站表过站状态
+ RecordPlcOperationResult(plcName, prodData);
return (true, prodData, successMsg);
}
catch (Exception ex)
{
- // 精细化异常日志,保留堆栈
- Console.WriteLine($"{plcName}({ip})生产数据读取异常:{ex.Message}\n{ex.StackTrace}");
return (false, null, $"{plcName}生产数据读取失败:{ex.Message}");
}
finally
@@ -529,7 +521,6 @@ namespace RIZO.Admin.WebApi.PLC.Service
}
catch (Exception ex)
{
- Console.WriteLine($"{plcName}({ip})释放PLC连接失败:{ex.Message}");
}
finally
{
@@ -539,7 +530,6 @@ namespace RIZO.Admin.WebApi.PLC.Service
}
}
-
#region 工位专属读取方法
///
/// 读取OP020-2数据(合盖工位
@@ -752,8 +742,8 @@ namespace RIZO.Admin.WebApi.PLC.Service
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 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["站位结果"]);
@@ -767,7 +757,7 @@ namespace RIZO.Admin.WebApi.PLC.Service
taskProductName, taskOrderName, taskProductModel, taskSN1, taskSN2,
// Int任务
taskRunStatus, taskMachineModel, taskOnlineStatus, taskByPass, taskProduceModel,
- taskQueryReq, taskSaveReq, taskTrayNo, taskCameraResult, taskStationResult,
+ taskTrayNo, taskCameraResult, taskStationResult,
// Real任务
taskCycleTime);
@@ -785,8 +775,6 @@ namespace RIZO.Admin.WebApi.PLC.Service
int onlineStatus = await taskOnlineStatus;
int byPass = await taskByPass;
int produceModel = await taskProduceModel;
- int queryReq = await taskQueryReq;
- int saveReq = await taskSaveReq;
int trayNo = await taskTrayNo;
int cameraResult = await taskCameraResult;
int stationResult = await taskStationResult;
@@ -879,8 +867,6 @@ namespace RIZO.Admin.WebApi.PLC.Service
var taskOnlineStatus = ReadPlcIntAsync(plc, _op075IntMap["设备在线状态"]);
var taskByPass = ReadPlcIntAsync(plc, _op075IntMap["ByPass"]);
var taskProduceModel = ReadPlcIntAsync(plc, _op075IntMap["生产模式"]);
- var taskQueryReq = ReadPlcIntAsync(plc, _op075IntMap["查询请求"]);
- var taskSaveReq = ReadPlcIntAsync(plc, _op075IntMap["保存请求"]);
var taskTrayNo = ReadPlcIntAsync(plc, _op075IntMap["托盘号"]);
var taskStationResult = ReadPlcIntAsync(plc, _op075IntMap["站位结果"]);
@@ -893,7 +879,7 @@ namespace RIZO.Admin.WebApi.PLC.Service
taskProductName, taskOrderName, taskProductModel, taskSN1, taskSN2, taskChipSN,
// Int任务
taskRunStatus, taskMachineModel, taskOnlineStatus, taskByPass, taskProduceModel,
- taskQueryReq, taskSaveReq, taskTrayNo, taskStationResult,
+ taskTrayNo, taskStationResult,
// Real任务
taskCycleTime);
@@ -912,8 +898,6 @@ namespace RIZO.Admin.WebApi.PLC.Service
int onlineStatus = await taskOnlineStatus;
int byPass = await taskByPass;
int produceModel = await taskProduceModel;
- int queryReq = await taskQueryReq;
- int saveReq = await taskSaveReq;
int trayNo = await taskTrayNo;
int stationResult = await taskStationResult;
@@ -2134,21 +2118,85 @@ namespace RIZO.Admin.WebApi.PLC.Service
}
}
- // 提取写PLC返回值的通用方法,统一处理逻辑和日志
+ // 提取写PLC返回值的通用方法,统一处理逻辑和日志
private void WritePlcSaveRequestResult(Plc plc, string ip, string plcName, PlcProductionData prodData, string saveResult)
{
try
{
WritePlcValue(plc, _mesIntReturnMap["设备使能"], "1");
- //WritePlcValue(plc, _mesIntReturnMap["工位开始查询结果"], "1");
+ WritePlcValue(plc, _mesIntReturnMap["工位开始查询结果"], "1");
WritePlcValue(plc, _mesIntReturnMap["保存结果"], saveResult);
- WritePlcValue(plc, "产品型号", prodData.ProductModel);
- WritePlcValue(plc, "订单下发", "");//??
+ 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)
{;
}
}
+
+ //记录PLC过站状态
+ private void RecordPlcOperationResult(string plcName, PlcProductionData prodData)
+ {
+ if (string.IsNullOrWhiteSpace(plcName))
+ {
+ throw new ArgumentNullException(nameof(plcName), "PLC/工位名称不能为空");
+ }
+ if (prodData == null)
+ {
+ throw new ArgumentNullException(nameof(prodData), "PLC生产数据实体不能为空");
+ }
+ string strSN = prodData.SN2?.Trim();
+ if (string.IsNullOrWhiteSpace(strSN))
+ {
+ return;
+ }
+ int result = string.Equals(prodData.QualificationFlag, "1", StringComparison.OrdinalIgnoreCase) ? 1 : 0;
+
+ try
+ {
+ var existingRecord = _plcOperationResultService.Queryable()
+ .Where(it => it.Sn == strSN && it.Workstationcode == plcName).ToList().FirstOrDefault();
+
+ if (existingRecord != null)
+ {
+ // 情况1:记录存在
+ if (existingRecord.Result == result)
+ {
+ return;
+ }
+ else
+ {
+ // 情况2:记录存在但结果不一致,执行修改操作
+ existingRecord.Result = result;
+ existingRecord.UpdatedBy = "PLC";
+ existingRecord.UpdatedTime = DateTime.Now;
+ _plcOperationResultService.Update(existingRecord);
+ }
+ }
+ else
+ {
+ // 情况3:记录不存在,执行新增操作
+ PlcOperationResult porNew = new PlcOperationResult();
+ porNew.Sn = strSN;
+ porNew.Workstationcode = plcName;
+ porNew.Result = result;
+ porNew.CreatedBy = "PLC";
+ porNew.CreatedTime = DateTime.Now;
+ _plcOperationResultService.Insert(porNew);
+ }
+ }
+ catch (Exception ex)
+ {
+ }
+ }
+
///
/// 异步复位上传请求(独立方法,非阻塞)
///
@@ -2180,5 +2228,68 @@ namespace RIZO.Admin.WebApi.PLC.Service
Console.WriteLine($"({ip})写保存请求复位失败:{ex.Message}");
}
}
+
+ ///
+ /// 向PLC写入字符串(字节数组形式)
+ ///
+ /// PLC客户端
+ /// 字符串起始地址(如DB1101.DBB1016)
+ /// PLC定义的字符串长度(如14)
+ /// 要写入的字符串
+ 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);
+ }
+
+ ///
+ /// PLC地址(如DB1101.DBB1016)
+ /// 数据类型(DB/Input等)
+ /// DB块编号(如1101)
+ /// 起始字节(如1016)
+ /// 是否解析成功
+ 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;
+ }
+ }
}
}
\ No newline at end of file
diff --git a/RIZO.Admin.WebApi/appsettings.json b/RIZO.Admin.WebApi/appsettings.json
index a5a379e..534c11a 100644
--- a/RIZO.Admin.WebApi/appsettings.json
+++ b/RIZO.Admin.WebApi/appsettings.json
@@ -97,8 +97,8 @@
"uniappPath": "D:\\Work" //h5前端代码存储路径
},
"GlobalConfig": {
- "ConnectTimeout": 5000, // 连接超时(毫秒)
- "ReadWriteTimeout": 5000 // 读写超时(毫秒)
+ "ConnectTimeout": 1000, // 连接超时(毫秒)
+ "ReadWriteTimeout": 1000 // 读写超时(毫秒)
},
"PlcPollingSettings": {
"MaxConcurrentPerPlc": 1,