Files

2297 lines
101 KiB
C#
Raw Permalink Normal View History

2026-09-07 08:07:08 +08:00
using JinYuan.Helper;
using JinYuan.MES.Models;
using JinYuan.Models;
using JinYuan.VirtualDataLibrary;
using Language;
using MiniExcelLibs;
using PLC;
using PLC.PLCAlarm;
using PLCCommunication;
using PLCCommunication.Common;
using PLCCommunication.Common.DataConvert;
using SqlSugar;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using DataType = PLC.DataType;
namespace JinYuan.ControlCenters
{
public partial class ControlCenter : IDisposable
{
private static readonly object uiLock = new object();
private static ControlCenter _instance;
public static ControlCenter Instance
{
get
{
lock (uiLock)
{
return _instance ??= new ControlCenter();
}
}
}
private readonly Dictionary<string, PlcGroup> groups = new Dictionary<string, PlcGroup>();
private Dictionary<string, Func<JYResult<byte[]>, PlcGroup, Task>> stationFunctions;
//private Dictionary<string, Action<JYResult<byte[]>, PlcGroup>> stationFunctions;
private readonly Dictionary<PlcReadWriteBase, List<PlcDevice>> plcDeviceMapping = new Dictionary<PlcReadWriteBase, List<PlcDevice>>();
private readonly Dictionary<string, Task> groupTasks = new Dictionary<string, Task>();
private readonly Dictionary<PlcReadWriteBase, PLCAlarmReader> plcAlarmReaders = new Dictionary<PlcReadWriteBase, PLCAlarmReader>();
private readonly ConcurrentDictionary<string, short> _lastOpenValues = new ConcurrentDictionary<string, short>();
public CancellationTokenSource _cts;
private Task _heartbeatTask;
private const int HeartbeatInterval = 1000; // 1 second
/// <summary>
/// 定时器-定时刷新状态和数据
/// </summary>
private System.Timers.Timer Timer_RefreshData;
private readonly string configFolderPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config");
private ControlCenter()
{
_cts = new CancellationTokenSource();
if (CommonMethods.plcDevices == null)
{
CommonMethods.plcDevices = new List<PlcReadWriteBase>();
}
InitializeDevicesFromExcel();
GetAlarmData();
InitFunc();
Timer_RefreshData = new System.Timers.Timer(1000);
Timer_RefreshData.Elapsed += Timer_RefreshData_Elapsed;
Timer_RefreshData.Start();
Thread thread = new Thread(ShowStateEven_Run);
thread.IsBackground = true;
thread.Start();
// 轴位置监控
Task.Run(() => { ShowAxleEven_Run(); });
// 电机位置监控
//Task.Run(() => { ShowMotorEven_Run(); });
//Mes心跳监控
Task.Run(new Action(() => { UpdateMesHeartBeat(); }));
//删除30天内日志
//DeleteLog.Start(CommonMethods.strDeletepath);//会把整个ApiLog删除
string[] clrPath = new string[] { CommonMethods.strAlarmLogspath, CommonMethods.strMesLogspath, CommonMethods.strWattrMeterpath, @"D:\Logs\" };
short[] seltWay = new short[] { 0, 0, 0, 1 };
DeleteLog.Start(clrPath, seltWay);
if (!CommonMethods.IsRun)
{
CommonMethods.ResetEventRecv.Reset();
}
}
/// <summary>
/// 初始化 工位方法,添加到字典里面
/// </summary>
private void InitFunc()
{
stationFunctions = new Dictionary<string, Func<JYResult<byte[]>, PlcGroup, Task>>
{
["电芯进站A"] = FeedingStationA,
["电芯进站B"] = FeedingStationB,
["电芯出站A"] = BlankingStationA,
["喷码工位A"] = JettingStationA,
["喷码工位B"] = JettingStationB,
["复投工位"] = ReInStation,
//["电芯出站B"] = BlankingStationB,
//["结构件料盘"] = MaterialStation,
// 根据需要添加更多站点功能
};
}
public async Task StartAsync()
{
CreatePLCThreads();
_heartbeatTask = StartHeartbeatCheck(_cts.Token);
await Task.CompletedTask;
}
#region PLC
private void InitializeDevicesFromExcel()
{
CommonMethods.AddDataMonitorLog(1, "开始加载配置参数……".Translated());
string deviceConfigPath = Path.Combine(configFolderPath, "Device.xlsx");
string groupConfigPath = Path.Combine(configFolderPath, "Group.xlsx");
string variableConfigPath = Path.Combine(configFolderPath, "Variable.xlsx");
string plcVariableConfigPath = Path.Combine(configFolderPath, "PLCVariable.xlsx");
if (!File.Exists(deviceConfigPath) || !File.Exists(groupConfigPath) || !File.Exists(variableConfigPath))
{
LogHelper.Instance.WriteError("配置文件不存在");
return;
}
try
{
var deviceConfigs = MiniExcel.Query<PlcDevice>(deviceConfigPath).ToList();
var groupConfigs = MiniExcel.Query<PlcGroup>(groupConfigPath).ToList();
var variableConfigs = MiniExcel.Query<PlcVariable>(variableConfigPath).ToList();
var plcVariableConfigs = MiniExcel.Query<PLCGroupVariable>(plcVariableConfigPath).ToList();
ConcurrentDictionary<string, PLCGroupVariable> PLCVariable = new ConcurrentDictionary<string, PLCGroupVariable>();
if (plcVariableConfigs.Count > 0)
{
foreach (PLCGroupVariable variable in plcVariableConfigs)
{
if (variable.VarAddress != null && !variable.VarAddress.Equals(""))
{
PLCVariable.TryAdd(variable.VarAddress.Trim(), variable);
}
}
}
CommonMethods.PLCVariable = PLCVariable;
foreach (var deviceConfig in deviceConfigs.Where(d => d.IsActive))
{
IPEndPoint iep = new IPEndPoint(IPAddress.Parse(deviceConfig.IPAddress), deviceConfig.Port);
PlcReadWriteBase plc = PLCFactory.CreatePLC(GetPLCTypeEnum(deviceConfig.PLCType), deviceConfig.PlcNum, $"PLC_{deviceConfig.PlcNum}", iep);
deviceConfig.Cts = new CancellationTokenSource();
deviceConfig.GroupList = groupConfigs
.Where(g => g.IsActive && g.PlcNum == deviceConfig.PlcNum)
.ToList();
foreach (var group in deviceConfig.GroupList)
{
group.VarList = variableConfigs
.Where(v => v.GroupName == group.GroupName && v.PlcNum == deviceConfig.PlcNum)
.ToList();
}
plcDeviceMapping[plc] = new List<PlcDevice> { deviceConfig };
CommonMethods.plcDevices.Add(plc);
string tmp = AppDomain.CurrentDomain.BaseDirectory;
// 初始化 PLCAlarm Reader报警读取
var alarmReader = new PLCAlarmReader(
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "AlarmConfig.csv"),
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "AlarmRecords"),
RecordType.RecordWhenFinish,
false
);
//alarmReader.PLCAlarm_New += AlrmReader_PLCAlarm_New;
//alarmReader.PLCAlarm_Remove += AlrmReader_PLCAlarm_Remove;
//plcAlarmReaders[plc] = alarmReader;
//CommonMethods.plcStatuses[plc] = new Dictionary<string, object>
//{
// ["OldStatus"] = (short)0,
// ["StatusCount"] = 0,
// ["GuidAlarm"] = string.Empty,
// ["Status"] = new List<bool> { false, false, false, false }
//};
}
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"加载配置失败:{ex.Message}");
}
CommonMethods.AddDataMonitorLog(1, "配置文件加载完成".Translated());
}
#region 创建PLC线程 几个工位就几个线程
/// <summary>
/// 按工位读取线程
/// </summary>
///
private readonly Dictionary<string, Thread> groupThreads = new Dictionary<string, Thread>();
private readonly object lockObject = new object();
private void CreatePLCThreads()
{
for (int i = 0; i < CommonMethods.plcDevices.Count; i++)
{
var plc = CommonMethods.plcDevices[i];
if (plcDeviceMapping.TryGetValue(plc, out var plcDevices))
{
foreach (var plcDevice in plcDevices)
{
foreach (var plcGroup in plcDevice.GroupList.Where(g => g.IsActive))
{
string threadKey = $"{plcDevice.PlcNum}-{plcGroup.GroupName}";
var parameter = (group: plcGroup, plcIndex: i);
Thread thread = new Thread(new ParameterizedThreadStart(ReadPLCWorkModel));
thread.IsBackground = true;
thread.Priority = ThreadPriority.Highest;
lock (lockObject)
{
groupThreads[threadKey] = thread;
}
thread.Start(parameter);
}
}
}
}
}
#endregion
#region 循环读取PLC工位状态
/// <summary>
/// 读取PLC循环工位
/// </summary>
/// <param name="plcModel"></param>
private void ReadPLCWorkModel(object parameter)
{
if (parameter is ValueTuple<PlcGroup, int> tuple)
{
var sw = new Stopwatch();
var (group, plcIndex) = tuple;
string groupKey = group.GroupName;
while (!_cts.Token.IsCancellationRequested)
{
if (CommonMethods.IsRun)
{
if (CommonMethods.plcDevices[plcIndex].IsConnected)
{
try
{
JYResult<short> OpenValue = CommonMethods.plcDevices[plcIndex].ReadValue<JYResult<short>>(group.VarList[0].VarAddress, DataType.Short);
// 获取上一次的值,如果不存在则默认为0
short lastValue = _lastOpenValues.GetOrAdd(groupKey, 0);
// 从0到1才执行
if (OpenValue.IsSuccess && OpenValue.Content == 1 && lastValue == 0)
{
LogHelper.Instance.WriteLog($"[{groupKey}] 检测到上升沿(0->1),开始处理", "PLC线程");
// 更新上一次的值
_lastOpenValues[groupKey] = 1;
sw.Restart();
JYResult<byte[]> resByte = CommonMethods.plcDevices[plcIndex].ReadValue<JYResult<byte[]>>($"{group.VarList[2].VarAddress}",
DataType.ArrByte, Convert.ToUInt16(group.VarList[2].OffsetOrLength));
sw.Stop();
LogHelper.Instance.WriteLog($"[{groupKey}] 读取数据区 {group.VarList[2].VarAddress}, " + $"长度={group.VarList[2].OffsetOrLength}, 成功={resByte?.IsSuccess},耗时:{sw.ElapsedMilliseconds}","PLC线程");
sw.Restart();
bool bRet = CommonMethods.plcDevices[plcIndex].WriteInt16(group.VarList[0].VarAddress, (short)2);
sw.Stop();
LogHelper.Instance.WriteLog($"[{groupKey}] 往{group.VarList[0].VarAddress}写2,写入结果:{bRet},耗时:{sw.ElapsedMilliseconds}ms","PLC线程");
if (!bRet)
{
bRet = CommonMethods.plcDevices[plcIndex].WriteInt16(group.VarList[0].VarAddress, (short)2);
LogHelper.Instance.WriteLog($"重试:往{group.VarList[0].VarAddress}写2,写入结果:{bRet}", "PLC线程");
}
if (resByte != null && stationFunctions.TryGetValue(group.GroupName, out var action))
{
LogHelper.Instance.WriteLog($"[{groupKey}] 开始执行工位逻辑", "PLC线程");
sw.Restart();
Task.Run(() => action(resByte, group));
sw.Stop();
LogHelper.Instance.WriteLog($"[{groupKey}] 工位逻辑执行完成,耗时:{sw.ElapsedMilliseconds}ms", "PLC线程");
}
else
{
bool bRet2 = CommonMethods.plcDevices[plcIndex].WriteInt16(group.VarList[0].VarAddress, (short)2);
LogHelper.Instance.WriteLog($"异常情况,resByte={resByte}为空或者{group.GroupName}找不到执行函数,往{group.VarList[0].VarAddress}写0,写入结果:{bRet2}", "PLC线程");
}
}
else if (OpenValue.IsSuccess && OpenValue.Content == 0)
{
// 当值变为0时,更新记录,以便下次0->1时触发
_lastOpenValues[groupKey] = 0;
}
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"错误: {group.GroupName} - {ex.Message}", "SysErrorLog");
var bRet = CommonMethods.plcDevices[plcIndex].WriteInt16(group.VarList[0].VarAddress, (short)0);
LogHelper.Instance.WriteLog($"异常场景下,往{group.VarList[0].VarAddress}写0,写入是否成功:{bRet}", "PLC线程");
}
}
}
Thread.Sleep(100);
}
}
}
#endregion
#region 开始停止联机事件
/// <summary>
/// 开始联机
/// </summary>
/// <returns></returns>
public async Task<bool> ConnectAllPlcsAsync()
{
bool allConnected = true;
if (CommonMethods.plcDevices.Count <= 0)
{
CommonMethods.AddDataMonitorLog(1, "无PLC配置信息".Translated() + "," + "请检查配置文件".Translated());
return allConnected = false;
}
foreach (var plc in CommonMethods.plcDevices)
{
if (plcDeviceMapping.TryGetValue(plc, out var plcDevices))
{
foreach (var deviceConfig in plcDevices)
{
string msg = "";
try
{
// 使用 Task.Run 来在后台线程执行连接操作
bool isConnected = await Task.Run(() =>
{
// 设置一个连接超时
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10))) // 10秒超时
{
try
{
return plc.Connect(ref msg);
}
catch (OperationCanceledException)
{
msg = "连接超时";
return false;
}
}
});
deviceConfig.IsConnected = isConnected;
if (!deviceConfig.IsConnected)
{
allConnected = false;
LogHelper.Instance.WriteLog($"连接PLC失败: {deviceConfig.PlcNum}, 错误: {msg}");
CommonMethods.AddDataMonitorLog(1, "连接PLC失败".Translated() + $": {deviceConfig.PlcNum}, " + "错误".Translated() + $": {msg}");
}
else
{
CommonMethods.AddDataMonitorLog(0, "成功连接PLC".Translated() + $": {deviceConfig.PlcNum}");
}
}
catch (Exception ex)
{
allConnected = false;
LogHelper.Instance.WriteLog($"连接PLC时发生异常: {deviceConfig.PlcNum}, 错误: {ex.Message}");
CommonMethods.AddDataMonitorLog(2, "连接PLC时发生异常".Translated() + $": {deviceConfig.PlcNum}" + "错误".Translated() + $": {ex.Message}");
}
}
}
}
return allConnected;
}
/// <summary>
/// 断开链接
/// </summary>
public void DisconnectAllPlcs()
{
foreach (var plc in CommonMethods.plcDevices)
{
if (plcDeviceMapping.TryGetValue(plc, out var plcDevices))
{
foreach (var deviceConfig in plcDevices)
{
plc.Disconnect();
deviceConfig.IsConnected = false;
CommonMethods.AddDataMonitorLog(0, "已断开与PLC".Translated() + $"[{deviceConfig.PlcNum}]" + "的链接".Translated());
}
}
}
}
#endregion
#endregion
#region MES
/// <summary>
/// Mes心跳
/// </summary>
private void UpdateMesHeartBeat()
{
Thread.Sleep(100);
while (true)//true
{
try
{
if (CommonMethods.mesConfig.IsLoginMesOK && CommonMethods.IsRun)//CommonMethods.mesConfig.isUpMes &&
{
if (Ping() == true)
{
CommonMethods.mesConfig.isConnected = true;
}
else//Ping失败,提示检查线路。
{
CommonMethods.mesConfig.isConnected = false;
if (DateTime.Now.Second % 10 == 0)
{
string errStr = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")},Mes心跳Ping失败,IP:{CommonMethods.mesConfig.MESURLAddressIP},端口号:{CommonMethods.mesConfig.MESURLAddressPort}";
TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{DateTime.Now.ToString("yyyyMMdd")}\Mes心跳报警\{DateTime.Now.ToString("HH")}.txt", errStr);
}
}
}
}
catch (Exception ex)
{
string errStr = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")},Mes心跳Ping异常,IP:{CommonMethods.mesConfig.MESURLAddressIP},端口号:{CommonMethods.mesConfig.MESURLAddressPort},原因:{ex.ToString()}";
TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{DateTime.Now.ToString("yyyyMMdd")}\Mes心跳报警\{DateTime.Now.ToString("HH")}.txt", errStr);
}
Thread.Sleep(1000);
}
}
/// <summary>
/// Ping 检查网络线路问题
/// </summary>
/// <returns></returns>
public bool Ping()
{
try
{
string strIP = CommonMethods.mesConfig.MESURLAddressIP;
int port = Convert.ToInt32(CommonMethods.mesConfig.MESURLAddressPort);
IPAddress ip = IPAddress.Parse(strIP);
IPEndPoint _endPoint = new IPEndPoint(ip, port);
if (_endPoint.Address == null)
{
return false;
}
Ping _ping = new Ping();
int timeout = 1000;
PingReply mPingRcv = _ping.Send(_endPoint.Address, timeout);
return (mPingRcv.Status == IPStatus.Success) ? true : false;
}
catch (Exception ex)
{
string errStr = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")},Mes心跳Ping异常,IP:{CommonMethods.mesConfig.MESURLAddressIP},端口号:{CommonMethods.mesConfig.MESURLAddressPort},原因:{ex.ToString()}";
TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{DateTime.Now.ToString("yyyyMMdd")}\Mes心跳报警\{DateTime.Now.ToString("HH")}.txt", errStr);
return false;
}
}
#endregion
#region 4、心跳和状态检查
/// <summary>
/// 心跳检测
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
private async Task StartHeartbeatCheck(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
if (CommonMethods.IsRun)
{
foreach (var plc in CommonMethods.plcDevices)
{
if (plcDeviceMapping.TryGetValue(plc, out var plcDevices))
{
foreach (var plcDevice in plcDevices)
{
if (plcDevice.IsActive && plcDevice.IsHeartBeat)
{
await CheckHeartbeatForDevice(plc, plcDevice);
//await ShowStateEven_RunAsync();
}
}
}
}
}
await Task.Delay(HeartbeatInterval, cancellationToken);
}
}
/// <summary>
///
/// </summary>
/// <param name="plc"></param>
/// <param name="plcDevice"></param>
/// <returns></returns>
private async Task CheckHeartbeatForDevice(PlcReadWriteBase plc, PlcDevice plcDevice)
{
if (plcDevice.IsConnected)
{
JYResult result;
try
{
result = await Task.Run(() => plc.ReadValue<JYResult<short>>(plcDevice.HeartBeat, DataType.Short));
}
catch (Exception ex)
{
plcDevice.ErrorTimes++;
plcDevice.IsConnected = false;
LogHelper.Instance.WriteLog($"PLC编号:{plcDevice.PlcNum} 读取心跳异常:{ex.Message}!!!");
return;
}
if (result.IsSuccess)
{
plcDevice.ErrorTimes = 0;
JYResult res;
try
{
res = await Task.Run(() => plc.WriteValue(plcDevice.HeartBeat, (short)1, DataType.Short));
}
catch (Exception ex)
{
plcDevice.IsConnected = false;
LogHelper.Instance.WriteError($"PLC编号:{plcDevice.PlcNum} 写入心跳异常:{ex.Message}!!!");
return;
}
if (!res.IsSuccess)
{
plcDevice.IsConnected = false;
LogHelper.Instance.WriteError($"PLC编号:{plcDevice.PlcNum}=心跳写入异常:{res.Message}!!!");
}
}
else
{
HandleHeartbeatFailure(plcDevice, result);
}
}
else
{
await ReconnectDevice(plc, plcDevice);
}
}
private void HandleHeartbeatFailure(PlcDevice plcDevice, JYResult result)
{
plcDevice.ErrorTimes++;
plcDevice.IsConnected = false;
if (plcDevice.ErrorTimes >= plcDevice.AllowErrorTimes)
{
LogHelper.Instance.WriteError($"编号:[{plcDevice.PlcNum}]的PLC链接断开:{result.Message}");
}
}
private async Task ReconnectDevice(PlcReadWriteBase plc, PlcDevice plcDevice)
{
if (!plcDevice.IsFirstConnect)
{
await Task.Delay(plcDevice.ReConnectTime);
try { plc.Disconnect(); }
catch (Exception ex)
{
LogHelper.Instance.WriteError($"编号:[{plcDevice.PlcNum}]的PLC断开链接异常:{ex.Message}");
}
}
string msg = "";
bool connectResult = false;
try
{
connectResult = await Task.Run(() => plc.Connect(ref msg));
}
catch (Exception ex)
{
msg = ex.Message;
connectResult = false;
}
plcDevice.IsConnected = connectResult;
LogHelper.Instance.WriteError(connectResult
? $"PLC编号:{plcDevice.PlcNum}{(plcDevice.IsFirstConnect ? "初次" : "重新")}连接成功{msg}!"
: $"[{plcDevice.PlcNum}]#PLC{(plcDevice.IsFirstConnect ? "初次" : "重新")}连接失败{msg}!");
plcDevice.IsFirstConnect = false;
}
#endregion
#region 定时刷新数据
int TotalNum = 0;
int TotalNum1 = 0;
int Regular = 0;
//int jetBeat = 0;
private void Timer_RefreshData_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (Regular >= 300)
{
Task.Run(() =>
{
GetEnergyDataFormSerialPort();
UploadEquEnergy();
});
Regular = 0;
}
if (TotalNum > 4)
{
//GetEnergyDataFormSerialPort();
Refresh12HourProdQty();
GetDefectTypeQty();
ReadPLCComm();
GetASqlAlarmData(DateTime.Today, CommonMethods.strClass);
TotalNum = 0;
}
else if (TotalNum == 2)//设备状态读取
{
SetClass(); //变更班次
}
//Task.Run(() =>
//{
// ShowStateEven_Run();
//});
if (TotalNum1 >= 3600 * 24)
{
Task.Run(() =>
{
DeleteFileOfLocal();
});
TotalNum1 = 0;
}
//电能表心跳
//if (jetBeat > 3)
//{
//if (CommonMethods.jetClientA.Connect()) { CommonMethods.jetClientA.connectState = true; }
//else { CommonMethods.jetClientA.connectState = false; }
//if (CommonMethods.jetClientB.Connect()) { CommonMethods.jetClientB.connectState = true; }
//else { CommonMethods.jetClientB.connectState = false; }
//if (!CommonMethods.energyMeter.Connected) { CommonMethods.energyMeter.Connect(); }
//jetBeat = 0;
//}
//jetBeat++;
TotalNum++;
TotalNum1++;
Regular++;
}
#endregion
#region 设备综合信息
/// <summary>
/// 读取PLC通用信息
/// </summary>
internal void ReadPLCComm()
{
if (CommonMethods.plcDevices.Count != 0 && CommonMethods.plcDevices[0].IsConnected)
{
Task.Run(async () =>
{
await UpTotalCount(null);
Thread.Sleep(50);
});
CommonMethods.TotalQty = CommonMethods.plcDevices[0].ReadFloat("D15");//生产总数
CommonMethods.ProOKQty = CommonMethods.plcDevices[0].ReadFloat("D17");//良品总数
CommonMethods.Ppm = CommonMethods.plcDevices[0].ReadFloat("D13");
CommonMethods.JiaDL = Convert.ToDouble(CommonMethods.plcDevices[0].ReadFloat("D11").ToString("F2"));
#region 开机时间/运行时间
CommonMethods.PlcOpenAndRunTime = GetList<int>(6, 0);
JYResult<byte[]> resByte = CommonMethods.plcDevices[0].ReadValue<JYResult<byte[]>>($"D50", DataType.ArrByte, 12);
if (resByte.IsSuccess && resByte.Content.Length >= 24)
{
for (int i = 0; i < CommonMethods.PlcOpenAndRunTimeAdress.Count; i++)
{
CommonMethods.PlcOpenAndRunTime[i] = ShortLib.GetShortFromByteArray(resByte.Content, i * 4, DataFormat.CDAB);
}
}
#endregion
}
}
#endregion
#region 保存12小时产能数据
public int totalNum = 0; // 总数
public int okNum = 0; // 良品数
/// <summary>
/// 储存数据到数据库
/// </summary>
/// <param name="DataCount"></param>
public async Task UpTotalCount(int[] DataCount)
{
try
{
DateTime dateTime = DateTime.Now;
string strDate = dateTime.ToString("yyyy-MM-dd");
// 获取当前时间的小时和分钟
int currentHour = dateTime.Hour;
int currentMinute = dateTime.Minute;
// 根据当前分钟确定统计小时
// 如果当前时间在 X:30 之前,则统计的是前一个小时的数据(从前一个小时的30分到这个小时的29分)
// 如果当前时间在 X:30 之后,则统计的是当前小时的数据(从当前小时的30分到下个小时的29分)
int statisticalHour;
if (currentMinute < 30)
{
statisticalHour = (currentHour + 23) % 24; // 前一个小时,处理跨天的情况
// 如果是凌晨0点前的数据,需要使用前一天的日期
if (currentHour == 0)
{
strDate = dateTime.AddDays(-1).ToString("yyyy-MM-dd");
}
}
else
{
statisticalHour = currentHour;
}
// 数据有效性验证
if (statisticalHour < 0 || statisticalHour > 23)
{
throw new ArgumentException($"无效的小时值: {statisticalHour}");
}
//读取统计小时的PLC投入总数和产出数
int ProdCurrAllQty = GetToDayHourQty(statisticalHour, true);
int ProdCurrOKQty = GetToDayHourQty(statisticalHour, false);
// 确保数量为非负数
if (ProdCurrAllQty < 0 || ProdCurrOKQty < 0)
{
LogHelper.Instance.WriteError($"产量不能为负数: 投入={ProdCurrAllQty}, 产出={ProdCurrOKQty}");
//throw new ArgumentException($"产量不能为负数: 投入={ProdCurrAllQty}, 产出={ProdCurrOKQty}");
}
Hourprod mh = new Hourprod
{
FDate = strDate,
FHour = statisticalHour,
ProdIn = ProdCurrAllQty,
ProdOut = ProdCurrOKQty,
TestTime = dateTime,
Ppm = (int)CommonMethods.Ppm,
JiaDL = Convert.ToDecimal(CommonMethods.JiaDL)
};
// 尝试更新记录
int res = CommonMethods.db.UpdateSingle(
mh,
it => new Hourprod
{
ProdIn = mh.ProdIn,
ProdOut = mh.ProdOut,
TestTime = mh.TestTime,
Ppm = mh.Ppm,
JiaDL = mh.JiaDL
},
it => it.FDate == mh.FDate && it.FHour == mh.FHour
);
// 如果更新失败(记录不存在),则新增记录
if (res <= 0)
{
bool addResult = await CommonMethods.db.AddReturnBoolAsync<Hourprod>(mh);
if (!addResult)
{
LogHelper.Instance.WriteError($"保存小时产能新增记录失败");
}
}
// 可以添加日志记录成功信息
// Logger.Log($"成功更新/新增产能数据: 日期={strDate}, 小时={statisticalHour}, 时段={statisticalHour}:30~{(statisticalHour + 1) % 24}:29");
}
catch (Exception ex)
{
// 这里应该添加错误日志记录
LogHelper.Instance.WriteEX($"保存小时产能数据失败: ", ex);
}
}
//string strErr = "";
//DateTime dateTime = DateTime.Now;
//string strDate = dateTime.ToString("yyyy-MM-dd");
//int Min = dateTime.Minute;
//int Hour = dateTime.Hour;
//if (Min < 30)
//{
// Hour -= 1;
//}
//if (dateTime.Hour < 30 && dateTime.Hour == 0)
//{
// Hour = 0;
//}
////读取PLC投入总数
//int ProdCurrAllQty = GetToDayHourQty(Hour, true);
////读取PLC产出数
//int ProdCurrOKQty = GetToDayHourQty(Hour, false);
//Hourprod mh = new Hourprod();
//mh.FDate = strDate;
//mh.FHour = Hour;
//mh.ProdIn = ProdCurrAllQty;
//mh.ProdOut = ProdCurrOKQty;
//mh.TestTime = DateTime.Now;
//mh.Ppm = CommonMethods.Ppm;
//mh.JiaDL = Convert.ToDecimal(CommonMethods.JiaDL);
////更新
//int res = CommonMethods.db.UpdateSingle(mh, it => new Hourprod() { ProdIn = mh.ProdIn, ProdOut = mh.ProdOut, TestTime = DateTime.Now, Ppm = mh.Ppm, JiaDL = mh.JiaDL, },
// it => it.FDate == mh.FDate && it.FHour == mh.FHour);
//if (res <= 0) //更新失败就新增保存
//{
// CommonMethods.db.AddReturnBool<Hourprod>(mh);
//}
/// <summary>
/// 每小时产能读取处理
/// </summary>
/// <param name="hour"></param>
/// <param name="flag"></param>
/// <returns></returns>
private int GetToDayHourQty(int hour, bool flag)
{
try
{
string strAddr = "";
if (flag)//产出
{
strAddr = "D" + (1040 + hour);
}
else//良品数
{
strAddr = "D" + (1070 + hour);
}
int ProdNGQty = CommonMethods.plcDevices[0].ReadInt16(strAddr);
return ProdNGQty;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "系统异常", MessageBoxButtons.OK, MessageBoxIcon.Hand);
}
return 0;
}
#endregion
#region 5、设备状态
/// <summary>
/// 定时获取设备状态
/// </summary>
/// <param name="mt"></param>
///
int OldStatues = Convert.ToInt32(IniConfigHelper.ReadIniData("上一次设备状态", "DeviceStatus", "1", CommonMethods.strDeviceStatusPath));//退出程序前设备状态
//int StatuesCount = 0;
DateTime StatuesBeginTime = DateTime.Now.AddMinutes(-6);
string strGuidAlarm = IniConfigHelper.ReadIniData("上一次Guid", "DeviceGuid", Guid.NewGuid().ToString(), CommonMethods.strDeviceStatusPath);//退出程序前Guid
bool run_AlarmMark = false;//特殊情况1标志(运行状态)
bool run_IdleMark = false;//特殊情况2标志(闲置状态)
bool isUpIdleAlarm = false;//闲置状态报警信息上传标志
List<AlarmData> idleAlarmData = new List<AlarmData>();//闲置状态的报警信息
private async void ShowStateEven_Run()
{
while (true)
{
try
{
if (CommonMethods.plcDevices.Count > 0 && CommonMethods.plcDevices != null)
{
if (CommonMethods.plcDevices[0] != null && CommonMethods.plcDevices[0].IsConnected)//检查plc配置是否启用
{
DateTime Date = DateTime.Now;
bool isUpload = false;
string deviceStatus = string.Empty;
string deviceStatusDesc = string.Empty;
short NewStatus = CommonMethods.plcDevices[0].ReadInt16("D10");//读取新状态
if (NewStatus != 100)
{
//特殊情况1:运行->报警->……->运行
if (NewStatus == 3 && OldStatues == 1) { run_AlarmMark = true; }//第一次进入报警状态
if (NewStatus == 1) { run_AlarmMark = false; }//下一次运行状态,置位
if (run_AlarmMark) { NewStatus = 3; }//报警状态后下一次运行状态期间一直是报警状态
//特殊情况2:运行->闲置->……->运行
if (NewStatus == 4 && OldStatues == 1) { run_IdleMark = true; }//第一次进入闲置状态
if (NewStatus == 1) { run_IdleMark = false; }//下一次闲置状态,置位
if (run_IdleMark) { NewStatus = 4; }//闲置状态后下一次运行状态期间一直是闲置状态
//闲置状态结束报警信息上传
if (OldStatues == 4 && NewStatus != 4 && isUpIdleAlarm)
{
_ = UpIdleDataAsync(idleAlarmData, strGuidAlarm);//guid
}
//设备状态信号灯变量
CommonMethods.Statues = new List<bool> { NewStatus == 1, NewStatus == 2, NewStatus == 3, NewStatus == 4 };//bool类型的4个true状态
// 状态切换时生成新的 GUID
if (NewStatus != OldStatues)
{
// 从 Alert 切换到非 Alert 状态时,上传报警信息
if (OldStatues == 3 && NewStatus != 3)
{
ShowAlarmEven_Run(strGuidAlarm, NewStatus);
}
// 只要状态变更,就生成新的 GUID
strGuidAlarm = Guid.NewGuid().ToString(); // 强制生成新的 GUID
isUpload = true;
//StatuesCount = 0;
OldStatues = NewStatus;
StatuesBeginTime = Convert.ToDateTime(Date);
//记录最新设备状态和Guid
//CommonMethods.UpdateConfig("MES_CONFIG", "DeviceStatus", NewStatus.ToString());// 保存设备状态到xml文件
//CommonMethods.UpdateConfig("MES_CONFIG", "Guid", strGuidAlarm);// 保存设备状态到xml文件
//CommonMethods.Configxml["MES_CONFIG"]["DeviceStatus"] = NewStatus.ToString(); // 保存设备状态到xml文件
//CommonMethods.Configxml["MES_CONFIG"]["Guid"] = strGuidAlarm; // 保存设备状态到xml文件
//CommonMethods.WriteXmlFile(CommonMethods.Configxml, CommonMethods.xmlFilePath);
IniConfigHelper.WriteIniData("上一次设备状态", "DeviceStatus", NewStatus.ToString(), CommonMethods.strDeviceStatusPath);
IniConfigHelper.WriteIniData("上一次Guid", "DeviceGuid", strGuidAlarm, CommonMethods.strDeviceStatusPath);
}
else
{
// 同种状态持续 5 分钟时上传状态信息
//StatuesCount++;
//if (StatuesCount >= 5 * 60)
//{
// isUpload = true;
// StatuesCount = 0;
//}
if (Date.Subtract(StatuesBeginTime).TotalSeconds >= 5 * 60)
{
isUpload = true;
StatuesBeginTime = DateTime.Now;
}
}
// 根据状态设置设备状态和描述
switch (NewStatus)
{
case 1:
deviceStatus = "Run";
deviceStatusDesc = "正常运行";
break;
case 2://取消
deviceStatus = "Maintain";
deviceStatusDesc = "停止运行";
break;
case 3:
deviceStatus = "Alert";
deviceStatusDesc = "故障调试";
// Alert 状态时上传报警信息
ShowAlarmEven_Run(strGuidAlarm, NewStatus);
LogHelper.Instance.WriteLog($"{strGuidAlarm}:设备进入Alert状态", "报警状态记录");
break;
case 4:
deviceStatus = "Idle";
deviceStatusDesc = "闲置待机";
ShowStuesEven_Run(strGuidAlarm);
break;
}
// 上传设备状态信息
if (CommonMethods.sysConfig.MesModeSwitching && CommonMethods.mesConfig.isConnected && isUpload && (NewStatus == 1 || NewStatus == 3 || NewStatus == 4))
{
var (success, message) = await CommonMethods.hbgMes.UploadEquStatusAsync(
CommonMethods.mesConfig.DeviceStatus,
CommonMethods.mesConfig.siteCode,//
CommonMethods.mesConfig.lineCode,//
CommonMethods.mesConfig.equipNum,//
CommonMethods.mesConfig.MaterialCode,//
CommonMethods.mesConfig.mesUserName,//
strGuidAlarm, // RUN 状态时传空
deviceStatus,
null
);
//if (success)
//{
// StatuesCount = 0;
//}
}
}
}
}
}
catch (Exception ex)
{
LogHelper.Instance.WriteEX(ex);
}
Thread.Sleep(100);
}
}
#region 触摸屏弹窗
private async void ShowStuesEven_Run(string strGuid)
{
if (CommonMethods.plcDevices[0].IsConnected)
{
string strCode = "";
string alarmName = "";
short HMIStatus = CommonMethods.plcDevices[0].ReadInt16("D40");
if (HMIStatus != 0)
{
CommonMethods.AddDataMonitorLog(0, "触发了手动HMI弹窗功能".Translated());
switch (HMIStatus) //注意:B1-D12都为闲置代码,上传代码是只需上传闲置代码
{
//case 1://取消
// strCode = "B1";
// alarmName = "计划维保";
// CommonMethods.AddDataMonitorLog(0, "B1 计划维保");
// break;
//case 2://取消
// strCode = "B2";
// alarmName = "无生产计划";
// CommonMethods.AddDataMonitorLog(0, "B2 无生产计划");
// break;
//case 3://取消
// strCode = "B3";
// alarmName = "样品、试产";
// CommonMethods.AddDataMonitorLog(0, "B3 样品、试产");
// break;
//case 4://取消
// strCode = "B4";
// alarmName = "其他计划停机";
// CommonMethods.AddDataMonitorLog(0, "B4.其他计划停机");
// break;
case 5:
strCode = "D1";
alarmName = "设备故障".Translated();
CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
break;
case 6:
strCode = "D2";
alarmName = "设备转型".Translated();
CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
break;
case 7:
strCode = "D3";
alarmName = "工程变更".Translated();
CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
break;
case 8:
strCode = "D4";
alarmName = "MES停机".Translated();
CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
break;
case 9:
strCode = "D5";
alarmName = "品质异常".Translated();
CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
break;
case 10:
strCode = "D6";
alarmName = "配件,物料更换".Translated();
CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
break;
case 11:
strCode = "D7";
alarmName = "来料不良".Translated();
CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
break;
case 12:
strCode = "D8";
alarmName = "待料".Translated();
CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
break;
case 13:
strCode = "D9";
alarmName = "品质检查".Translated();
CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
break;
case 14:
strCode = "D10";
alarmName = "清洁点检".Translated();
CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
break;
case 15:
strCode = "D11";
alarmName = "环境不满足".Translated();
CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
break;
case 16:
strCode = "D12";
alarmName = "其它非计划停机".Translated();
CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
break;
default:
break;
}
if (CommonMethods.sysConfig.MesModeSwitching && CommonMethods.mesConfig.isConnected)
{
List<AlarmData> alarmObj = new List<AlarmData>();
AlarmData alarmData = new AlarmData();
alarmData.AlarmCode = strCode;
alarmData.StartTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
alarmData.EndTime = "";
alarmData.AlarmType = "非计划损失";
alarmData.AlarmContent = alarmName;
alarmObj.Add(alarmData);
//闲置报警上传标志
isUpIdleAlarm = true;
idleAlarmData.Add(alarmData);
//上传报警
var (success, message) = await CommonMethods.hbgMes.UploadEquAlarmAsync(CommonMethods.mesConfig.DeviceAlarm, CommonMethods.mesConfig.siteCode, CommonMethods.mesConfig.lineCode,
CommonMethods.mesConfig.equipNum, CommonMethods.mesConfig.MaterialCode, CommonMethods.mesConfig.mesUserName, alarmObj, strGuid);
if (success)
CommonMethods.AddDataMonitorLog(0, "HMI手动弹窗状态已上传成功,代码".Translated() + $":{strCode}");
}
bool IsSuccess = CommonMethods.plcDevices[0].WriteInt16("D40", 0);
if (IsSuccess)
CommonMethods.AddDataMonitorLog(0, $"D40已复位0".Translated());
}
}
}
#endregion
/// <summary>
/// HMI手动弹窗结束状态上传
/// </summary>
/// <param name="idleAlarmDate"></param>
/// <param name="strGuidAlarm"></param>
/// <returns></returns>
private async Task UpIdleDataAsync(List<AlarmData> idleAlarmDate, string strGuidAlarm)
{
if (idleAlarmDate.Count == 0) { return; }
string strCode = "";
foreach (var item in idleAlarmDate)
{
item.EndTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
strCode = item.AlarmCode + ",";
}
if (CommonMethods.sysConfig.MesModeSwitching && CommonMethods.mesConfig.isConnected)
{
//上传报警
var (success, message) = await CommonMethods.hbgMes.UploadEquAlarmAsync(CommonMethods.mesConfig.DeviceAlarm, CommonMethods.mesConfig.siteCode, CommonMethods.mesConfig.lineCode,
CommonMethods.mesConfig.equipNum, CommonMethods.mesConfig.MaterialCode, CommonMethods.mesConfig.mesUserName, idleAlarmDate, strGuidAlarm);
if (success)
CommonMethods.AddDataMonitorLog(0, "HMI手动弹窗结束状态已上传成功,代码".Translated() + $":{strCode.TrimEnd(',')}");
}
idleAlarmData.Clear();
isUpIdleAlarm = false;
}
#endregion
#region 6、设备报警
//报警表单数据
List<AlarmForm> listAlarmForm = null;
public void GetAlarmData()
{
//加载PLC报警文件
try
{
string strFileName = System.Environment.CurrentDirectory + "\\欧姆龙报警寄存器对应表.csv";
listAlarmForm = CSVHelper<AlarmForm>.ReadCSV<AlarmForm>(strFileName);
}
catch (Exception ex)
{
MessageBox.Show("加载报警文件失败!");
}
}
/// <summary>
/// 报警信息读取
/// </summary>
/// <param name="mt"></param>
/// <param name="resByte"></param>
List<AlarmData> listOld = new List<AlarmData>();//旧报警信息表
List<AlarmData> listNew = new List<AlarmData>();//新报警信息表
private void ShowAlarmEven_Run(string strGuidAlarm, int MachineState)
{
if (!CommonMethods.IsRun || !CommonMethods.plcDevices[0].IsConnected)
{
return;
}
try
{
// 1. 读取 PLC 报警信息
List<AlarmStatus> alarmStatusList = ReadAlarmStatusFromPLC();
if (alarmStatusList == null || listAlarmForm == null)//true
{
return;
}
// 2. 解析报警信息并生成新的报警列表
List<AlarmData> newAlarms = ParseAlarmStatus(alarmStatusList, strGuidAlarm);
if (newAlarms.Count > 0)
{
LogHelper.Instance.WriteLog($"{strGuidAlarm}: 报警信息为 {string.Join(" | ", newAlarms)}", "报警状态记录");
// 3. 检测新报警并添加到旧报警列表,上传第一次报警信息
DetectNewAlarmsAsync(newAlarms);
// 4. 文字显示新报警信息
DisplayAlarmInfo(newAlarms);
}
// 5. 检测已取消的报警并处理
List<AlarmData> canceledAlarms = DetectCanceledAlarms(newAlarms);
if (canceledAlarms.Count > 0)
{
// 6. 记录已取消的报警信息(保存本地)
LogCanceledAlarms(canceledAlarms);
// 7. 上传已取消的报警信息(报警结束上传一次)
UploadCanceledAlarmsAsync(canceledAlarms, strGuidAlarm);
}
if (MachineState != 3 && listOld.Count > 0) //设备状态变为非报警并旧报警仍有报警。旧报警上传并清空
{
List<AlarmData> tempOldAlarmList = new List<AlarmData>();
foreach (var item in listOld)
{
item.EndTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); //所有报警全部结束时间赋值
tempOldAlarmList.Add(item);
}
// 6. 记录已取消的报警信息(保存本地)
LogCanceledAlarms(tempOldAlarmList);
// 7. 上传已取消的报警信息(报警结束上传一次)
UploadCanceledAlarmsAsync(tempOldAlarmList, strGuidAlarm);
listOld.Clear();
}
}
catch (Exception ex)
{
LogHelper.Instance.WriteEX(ex);
}
}
/// <summary>
/// 从 PLC 读取报警状态
/// </summary>
private List<AlarmStatus> ReadAlarmStatusFromPLC()
{
//string Date = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
//JYResult<byte[]> resByte = CommonMethods.plcDevices[0].ReadValue<JYResult<byte[]>>("D10150", DataType.ArrByte, 5000);
//if (resByte.IsSuccess && resByte != null)
//{
// int startPlcAddr = 10150; // 读取起始地址
// return PLCAlarmParseHelper.OmronFinsByte2Status(startPlcAddr, resByte.Content);
//}
string Date = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
// 读取足够的字节覆盖所有可能的报警地址
int startAddr = 10150;
int endAddr = 14750; // 根据实际最大地址调整
int wordCount = endAddr - startAddr + 1;
int byteCount = wordCount * 2; // 每个字2字节
JYResult<byte[]> resByte = CommonMethods.plcDevices[0].ReadValue<JYResult<byte[]>>(
$"D{startAddr}", DataType.ArrByte, (ushort)byteCount);
if (resByte.IsSuccess && resByte.Content != null)
{
return PLCAlarmParseHelper.OmronFinsByte2Status(startAddr, resByte.Content);
}
return null;
}
/// <summary>
/// 解析报警状态并生成新的报警列表
/// </summary>
private List<AlarmData> ParseAlarmStatus(List<AlarmStatus> alarmStatusList, string strGuidAlarm)
{
string Date = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
var alarmTypeMap = new Dictionary<char, string> // 定义报警类型映射字典
{
{'1', "停机报警"},
{'2', "非停机报警"},
};
switch (LanguageManager.LanguageCode)
{
case "en"://英语报警信息
return alarmStatusList
.Where(status => status.Status)
.Join(
listAlarmForm,
status => status.PLCAdress,
form => form.PLCAdress,
(status, form) =>
{
var alarmContent = string.IsNullOrEmpty(form.EnAlarmContent)
? status.PLCAdress
: form.EnAlarmContent;
string alarmType = "停机报警"; // 默认值
if (form.AlarmCode?.Length >= 3)
{
char thirdChar = form.AlarmCode[2];
// 尝试从字典获取对应的值
if (alarmTypeMap.TryGetValue(thirdChar, out string mappedType))
{
alarmType = mappedType;
}
}
return new AlarmData
{
AlarmGuid = strGuidAlarm,
PLCAdress = status.PLCAdress,
AlarmCode = form.AlarmCode,
AlarmContent = alarmContent,
AlarmType = alarmType,
AlarmDesc = alarmContent,
AlarmState = "1",
StartTime = Date,
EndTime = "",
Flag = 0
};
})
.ToList();
case "hu"://匈牙利语报警信息
return alarmStatusList
.Where(status => status.Status)
.Join(
listAlarmForm,
status => status.PLCAdress,
form => form.PLCAdress,
(status, form) =>
{
var alarmContent = string.IsNullOrEmpty(form.HuAlarmContent)
? status.PLCAdress
: form.HuAlarmContent;
string alarmType = "停机报警"; // 默认值
if (form.AlarmCode?.Length >= 3)
{
char thirdChar = form.AlarmCode[2];
// 尝试从字典获取对应的值
if (alarmTypeMap.TryGetValue(thirdChar, out string mappedType))
{
alarmType = mappedType;
}
}
return new AlarmData
{
AlarmGuid = strGuidAlarm,
PLCAdress = status.PLCAdress,
AlarmCode = form.AlarmCode,
AlarmContent = alarmContent,
AlarmType = alarmType,
AlarmDesc = alarmContent,
AlarmState = "1",
StartTime = Date,
EndTime = "",
Flag = 0
};
})
.ToList();
case "ms"://马来语报警信息
return alarmStatusList
.Where(status => status.Status)
.Join(
listAlarmForm,
status => status.PLCAdress,
form => form.PLCAdress,
(status, form) =>
{
var alarmContent = string.IsNullOrEmpty(form.MsAlarmContent)
? status.PLCAdress
: form.MsAlarmContent;
string alarmType = "停机报警"; // 默认值
if (form.AlarmCode?.Length >= 3)
{
char thirdChar = form.AlarmCode[2];
// 尝试从字典获取对应的值
if (alarmTypeMap.TryGetValue(thirdChar, out string mappedType))
{
alarmType = mappedType;
}
}
return new AlarmData
{
AlarmGuid = strGuidAlarm,
PLCAdress = status.PLCAdress,
AlarmCode = form.AlarmCode,
AlarmContent = alarmContent,
AlarmType = alarmType,
AlarmDesc = alarmContent,
AlarmState = "1",
StartTime = Date,
EndTime = "",
Flag = 0
};
})
.ToList();
case "zh":
default:
return alarmStatusList
.Where(status => status.Status)
.Join(
listAlarmForm,
status => status.PLCAdress,
form => form.PLCAdress,
(status, form) =>
{
var alarmContent = string.IsNullOrEmpty(form.AlarmContent)
? status.PLCAdress
: form.AlarmContent;
string alarmType = "停机报警"; // 默认值
if (form.AlarmCode?.Length >= 3)
{
char thirdChar = form.AlarmCode[2];
// 尝试从字典获取对应的值
if (alarmTypeMap.TryGetValue(thirdChar, out string mappedType))
{
alarmType = mappedType;
}
}
return new AlarmData
{
AlarmGuid = strGuidAlarm,
PLCAdress = status.PLCAdress,
AlarmCode = form.AlarmCode,
AlarmContent = alarmContent,
AlarmType = alarmType,
AlarmDesc = alarmContent,
AlarmState = "1",
StartTime = Date,
EndTime = "",
Flag = 0
};
})
.ToList();
}
#region
/*string Date = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
switch (LanguageManager.LanguageCode)
{
case "en"://英语报警信息
return alarmStatusList
.Where(s => s.Status)
.Join(listAlarmForm, s => s.PLCAdress, f => f.PLCAdress, (s, f) => new AlarmData()
{
AlarmGuid = strGuidAlarm,
PLCAdress = s.PLCAdress,
AlarmCode = f.AlarmCode,
AlarmContent = f.EnAlarmContent == "" ? s.PLCAdress : f.EnAlarmContent,
AlarmType = "停机报警",
AlarmDesc = f.EnAlarmContent == "" ? s.PLCAdress : f.EnAlarmContent,
AlarmState = "1",
StartTime = Date,
EndTime = "",//Date
Flag = 0
}).ToList();
case "hu"://匈牙利语报警信息
return alarmStatusList
.Where(s => s.Status)
.Join(listAlarmForm, s => s.PLCAdress, f => f.PLCAdress, (s, f) => new AlarmData()
{
AlarmGuid = strGuidAlarm,
PLCAdress = s.PLCAdress,
AlarmCode = f.AlarmCode,
AlarmContent = f.HuAlarmContent == "" ? s.PLCAdress : f.HuAlarmContent,
AlarmType = "停机报警",
AlarmDesc = f.HuAlarmContent == "" ? s.PLCAdress : f.HuAlarmContent,
AlarmState = "1",
StartTime = Date,
EndTime = "",//Date
Flag = 0
}).ToList();
case "ms"://马来语报警信息
return alarmStatusList
.Where(s => s.Status)
.Join(listAlarmForm, s => s.PLCAdress, f => f.PLCAdress, (s, f) => new AlarmData()
{
AlarmGuid = strGuidAlarm,
PLCAdress = s.PLCAdress,
AlarmCode = f.AlarmCode,
AlarmContent = f.MsAlarmContent == "" ? s.PLCAdress : f.MsAlarmContent,
AlarmType = "停机报警",
AlarmDesc = f.MsAlarmContent == "" ? s.PLCAdress : f.MsAlarmContent,
AlarmState = "1",
StartTime = Date,
EndTime = "",//Date
Flag = 0
}).ToList();
case "zh"://中语报警信息
default:
return alarmStatusList
.Where(s => s.Status)
.Join(listAlarmForm, s => s.PLCAdress, f => f.PLCAdress, (s, f) => new AlarmData()
{
AlarmGuid = strGuidAlarm,
PLCAdress = s.PLCAdress,
AlarmCode = f.AlarmCode,
AlarmContent = f.AlarmContent == "" ? s.PLCAdress : f.AlarmContent,
//AlarmType = "停机报警",
AlarmType = f.AlarmCode.Length > 3 && f.AlarmCode[2]!= '2' ? "停机报警":"非停机报警",
AlarmDesc = f.AlarmContent == "" ? s.PLCAdress : f.AlarmContent,
AlarmState = "1",
StartTime = Date,
EndTime = "",//Date
Flag = 0
}).ToList();
}*/
#endregion
}
// List<AlarmData> datas = new List<AlarmData>();
private string UploadedAlarmContent = string.Empty;
/// <summary>
/// 检测新报警并添加到旧报警列表
/// </summary>
private void DetectNewAlarmsAsync(List<AlarmData> newAlarms)
{
List<AlarmData> tempAlarmList = new List<AlarmData>();
foreach (var alarm in newAlarms)
{
if (!listOld.Any(o => o.PLCAdress == alarm.PLCAdress))
{
listOld.Add(alarm);
tempAlarmList.Add(alarm); //把新报警保存到临时表中
}
}
if (CommonMethods.sysConfig.MesModeSwitching && CommonMethods.mesConfig.isConnected)
{
CommonMethods.hbgMes.UploadEquAlarmAsync(
CommonMethods.mesConfig.DeviceAlarm,
CommonMethods.mesConfig.siteCode,
CommonMethods.mesConfig.lineCode,
CommonMethods.mesConfig.equipNum,
CommonMethods.mesConfig.MaterialCode,
CommonMethods.mesConfig.mesUserName,
tempAlarmList,
strGuidAlarm
);
}
}
/// <summary>
/// 显示报警信息
/// </summary>
private void DisplayAlarmInfo(List<AlarmData> newAlarms)
{
StringBuilder sb = new StringBuilder();
newAlarms.ForEach(r => sb.Append($"{r.AlarmContent} "));//去掉空格
if (sb.Length > 0)
{
CommonMethods.SlideAlarmText = sb.ToString().Substring(0, sb.Length - 10);
}
}
/// <summary>
/// 检测已取消的报警
/// </summary>
private List<AlarmData> DetectCanceledAlarms(List<AlarmData> newAlarms)
{
var canceledAlarms = new List<AlarmData>();
var listOldAlarm = new List<AlarmData>(listOld);
foreach (var item in listOldAlarm)
{
if (!newAlarms.Any(n => n.PLCAdress == item.PLCAdress))
{
item.EndTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
canceledAlarms.Add(item);
listOld.Remove(item);
}
}
return canceledAlarms;
}
/// <summary>
/// 记录已取消的报警信息
/// </summary>
private void LogCanceledAlarms(List<AlarmData> canceledAlarms)
{
var nowDate = DateTime.Now;
string basePath = $@"{CommonMethods.strAlarmLogspath}\{nowDate.Year}\{nowDate.Month}";
string fileName = $@"{nowDate.Day}.csv";
string title = "GUID,报警地址,故障代码,报警内容,开始时间,结束时间,是否停机";
string alarmContent = string.Join("\n", canceledAlarms.Select(m1 =>
$"{m1.AlarmGuid},{m1.PLCAdress},{m1.AlarmCode},{m1.AlarmContent},{m1.StartTime},{m1.EndTime},{m1.AlarmType}"));
CSVHelper<AlarmCSVData>.WriterCSV(basePath, fileName, title, alarmContent);
foreach (var m1 in canceledAlarms)
{
var alarm = new SysLog
{
InsertTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
LogType = "报警日志",
Note = m1.AlarmContent == "" ? m1.PLCAdress : m1.AlarmContent,
AlarmType = "错误",
Operater = CommonMethods.currentAdmin.LoginName,
VarName = m1.PLCAdress,
AlarmSet = "",
AlarmValue = "1",
};
CommonMethods.AddAlarmLog(alarm);
Task.Run(() => { SaveAlarmCount(canceledAlarms); Thread.Sleep(50); });
}
}
/// <summary>
/// 上传已取消的报警信息
/// </summary>
private void UploadCanceledAlarmsAsync(List<AlarmData> canceledAlarms, string strGuidAlarm)
{
//for (int i = 0; i < canceledAlarms.Count; i++)
//{
// if (canceledAlarms[i].EndTime.Length > 1)
//// {
// var alarm = new List<AlarmData> { canceledAlarms[i] };
if (CommonMethods.sysConfig.MesModeSwitching)
{
CommonMethods.hbgMes.UploadEquAlarmAsync(
CommonMethods.mesConfig.DeviceAlarm,
CommonMethods.mesConfig.siteCode,
CommonMethods.mesConfig.lineCode,
CommonMethods.mesConfig.equipNum,
CommonMethods.mesConfig.MaterialCode,
CommonMethods.mesConfig.mesUserName,
canceledAlarms,
strGuidAlarm
);
}
// }
//}
//// datas.Clear();
//listOld.Clear();
}
/// <summary>
/// 报警保存
/// </summary>
private async Task SaveAlarmCount(List<AlarmData> alarmDatas)
{
bool ISAdd = false;
var recordToUpdate = new AlarmCountEntry();
DateTime today = DateTime.Today;
DateTime upTime = DateTime.Now;
var listAlarmStatistics = CommonMethods.db.QueryWhereList<AlarmCountEntry>(it => Convert.ToDateTime(it.AlarmTime.ToString("yyyy-MM-dd")) == today);
List<AlarmCountEntry> fd = new List<AlarmCountEntry>();
if (listAlarmStatistics != null)
{
alarmDatas.ForEach(async r =>
{
recordToUpdate = listAlarmStatistics.FirstOrDefault(x => x.PLCAdress.Trim() == r.PLCAdress);
if (recordToUpdate != null)
{
await CommonMethods.db.UpdateAsync<AlarmCountEntry>(it => it.AlarmCount == it.AlarmCount + 1, it => it.PLCAdress == r.PLCAdress && Convert.ToDateTime(it.AlarmTime.ToString("yyyy-MM-dd")) == today);
}
else
{
ISAdd = true;
AlarmCountEntry alarm = new AlarmCountEntry();
alarm.PLCAdress = r.PLCAdress;
alarm.AlarmContent = r.AlarmContent;
alarm.AlarmCount = 1;
alarm.Class = CommonMethods.strClass;
alarm.AlarmTime = upTime;
fd.Add(alarm);
}
});
if (ISAdd)
{
bool res = await CommonMethods.db.AddReturnBoolAsync(fd);
ISAdd = false;
}
}
// 显示报警信息方法已存数据库,报警TOP10就插入新增了
//else
//{
// foreach (var m in listNew)
// {
// AlarmCountEntry alarm = new AlarmCountEntry();
// alarm.PLCAdress = m.PLCAdress;
// alarm.AlarmContent = m.AlarmContent;
// alarm.AlarmCount = 1;
// alarm.Class = CommonMethods.strClass;
// alarm.AlarmTime = today;
// fd.Add(alarm);
// }
// await CommonMethods.db.AddReturnBoolAsync(fd);
//}
await GetASqlAlarmData(DateTime.Today, CommonMethods.strClass);
}
/// <summary>
/// 读取数据库报警信息
/// </summary>
/// <param name="today"></param>
/// <param name="strClass"></param>
public async Task GetASqlAlarmData(DateTime today, string strClass)
{
try
{
List<ChartDataType> chartAlarms = new List<ChartDataType>();
List<AlarmCountEntry> AlarmDatas = null;
List<string> List_X = new List<string>();
List<int> List_Y = new List<int>();
DateTime baiClassStart = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd 8:30:00"));
DateTime baiClassEnd = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd 20:29:59"));
DateTime yeClassStart = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd 20:30:00"));
DateTime yeClassEnd = Convert.ToDateTime(DateTime.Now.AddDays(1).ToString("yyyy-MM-dd 8:29:59"));
if (strClass == "全天".Translated())
{
AlarmDatas = CommonMethods.db.QueryList<AlarmCountEntry>("AlarmCount", 10, it => Convert.ToDateTime(it.AlarmTime.ToString("yyyy-MM-dd")) == today);
}
else if (strClass == "白班".Translated())
{
AlarmDatas = CommonMethods.db.QueryList<AlarmCountEntry>("AlarmCount", 10, it => it.AlarmTime >= baiClassStart && it.AlarmTime <= baiClassEnd && it.Class == strClass);
}
else
{
AlarmDatas = CommonMethods.db.QueryList<AlarmCountEntry>("AlarmCount", 10, it => it.AlarmTime >= yeClassStart && it.AlarmTime <= yeClassEnd && it.Class == strClass);
}
if (AlarmDatas != null && AlarmDatas.Count > 0)
{
for (int i = 0; i < AlarmDatas.Count; i++)
{
chartAlarms.Add(new ChartDataType()
{
DataType = AlarmDatas[i].AlarmContent,
DataCount = (int)AlarmDatas[i].AlarmCount
});
}
CommonMethods.Lst_AlarmTop10_Qty = chartAlarms;
}
else
{
CommonMethods.Lst_AlarmTop10_Qty = null;
}
}
catch (Exception)
{
}
}
#endregion
#region 下发权限给PLC
/// <summary>
/// 下发权限到PLC
/// </summary>
///
private async Task SendRightToPLCAsync()
{
ushort quanxian = 1;
switch (CommonMethods.currentAdmin.LoginLevel)
{
case "操作员":
quanxian = 1;
break;
case "工程师":
quanxian = 2;
break;
case "管理员":
quanxian = 3;
break;
default:
break;
}
foreach (var plc in CommonMethods.plcDevices)
{
if (plcDeviceMapping.TryGetValue(plc, out var plcDevices))
{
foreach (var plcDevice in plcDevices)
{
if (plcDevice.IsConnected)
{
JYResult result = await Task.Run(() => plc.WriteValue("D21", (short)quanxian, DataType.Short));
if (result.IsSuccess)
{
CommonMethods.AddDataMonitorLog(1, $"Write_PLC_permission_Successful");
}
else
{
CommonMethods.AddDataMonitorLog(2, $"Write_PLC_permission(D15)_Failed");
}
}
}
}
}
}
#endregion
#region 获取白夜班次
bool qiehuan = false;
private void SetClass()
{
try
{
var nowDate = DateTime.Now;
string strClass = "";
DateTime time1 = Convert.ToDateTime($"{nowDate.ToShortDateString()} {CommonMethods.ChangeClassTime}");
DateTime time2 = Convert.ToDateTime($"{nowDate.ToShortDateString()} {Convert.ToDateTime(CommonMethods.ChangeClassTime).AddHours(12).ToString("HH:mm:ss")}");
if (nowDate <= time1 && nowDate >= time2)
{
if (CommonMethods.plcDevices[0].IsConnected)
{
if (!qiehuan)
{
if (!SetPlcTime())
{
CommonMethods.AddLog(true, $"PC写入PLC时间失败!".Translated());
}
else
{
qiehuan = true;
CommonMethods.AddLog(false, "PC写入PLC时间成功!".Translated());
}
}
}
strClass = "白班".Translated();
}
else
{
qiehuan = false;
strClass = "夜班".Translated();
}
CommonMethods.strClass = strClass;
}
catch (Exception ex)
{
CommonMethods.AddLog(true, "PC写入PLC时间异常".Translated() + ":" + ex.Message);
LogHelper.Instance.WriteEX(ex);
}
}
#endregion
#region 写入PLC时间
/// <summary>
/// 写当前时间给PLC
/// </summary>
private bool SetPlcTime()
{
var nowDate = DateTime.Now;
string yearStr = nowDate.Year.ToString();
bool IsSuccess = false;
// 为防止PLC时间出现偏差,每次自动运行的时候写PLC系统时间
short[] writeArr = new short[]
{
Convert.ToInt16(nowDate.Year),//D70
Convert.ToInt16(nowDate.Month),//D71
Convert.ToInt16(nowDate.Day),//D72
Convert.ToInt16(nowDate.Hour),//D73
Convert.ToInt16(nowDate.Minute),//D74
Convert.ToInt16(nowDate.Second),//D75
(short)1 //D76
};
if (CommonMethods.plcDevices[0].IsConnected)
{
JYResult result = CommonMethods.plcDevices[0].WriteValue("D70", writeArr, DataType.ArrShort);
if (result.IsSuccess)
{
IsSuccess = true;
}
}
return IsSuccess;
}
#region 8、IDisposable 实现
// 如果需要在StopAsync中也显示进度,可以添加一个进度回调
private Task processTask;
public async Task StopAsync(IProgress<string> progress = null)
{
_cts.Cancel();
if (_heartbeatTask != null)
{
progress?.Report("正在停止心跳任务...");
try
{
await _heartbeatTask;
}
catch (OperationCanceledException)
{
// 忽略取消异常
}
}
if (processTask != null)
{
progress?.Report("正在停止处理任务...");
try
{
await processTask;
}
catch (OperationCanceledException)
{
// 忽略取消异常
}
}
foreach (var pair in groupTasks)
{
progress?.Report($"正在停止组任务: {pair.Key}...");
try
{
await pair.Value;
}
catch (OperationCanceledException)
{
// 忽略取消异常
}
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_cts?.Cancel();
_cts?.Dispose();
processTask?.Wait();
// 断开所有设备连接
foreach (var plc in CommonMethods.plcDevices)
{
plc.Disconnect();
if (plcAlarmReaders.TryGetValue(plc, out var alarmReader))
{
//alarmReader.PLCAlarm_New -= AlrmReader_PLCAlarm_New;
//alarmReader.PLCAlarm_Remove -= AlrmReader_PLCAlarm_Remove;
}
}
CommonMethods.plcDevices.Clear();
plcDeviceMapping.Clear();
plcAlarmReaders.Clear();
CommonMethods.plcStatuses.Clear();
DisconnectAllPlcs();
}
}
#endregion
#endregion
#region 7、辅助方法
private static PLCType GetPLCTypeEnum(string plcTypeString)
{
if (Enum.TryParse(plcTypeString, out PLCType plcType))
{
return plcType;
}
throw new ArgumentException($"PLC 类型无效: {plcTypeString}");
}
#endregion
#region 8、轴/电机位置监控
private void ReadAxleCSV(int flag, ref List<AxleLog> axleLog, ref List<MotorLog> motorLog)
{
axleLog = new List<AxleLog>();
motorLog = new List<MotorLog>();
try
{
string strLine = "";
string[] csvReset;//轴位置暂存
string PlcAddress = string.Empty;
bool isExits = false;
switch (flag)
{
case 1://本机轴设定位置
IniConfigHelper.CreateIniFile(configFolderPath, "Motor_GunBiaoAxle.ini");
if (!File.Exists(Path.Combine(configFolderPath, "Motor_GunBiaoAxle.ini")))//判断ini文件是否存在
{
isExits = true;
}
using (StreamReader reader = new StreamReader(Path.Combine(configFolderPath, "Motor_GunBiaoAxle.csv"), System.Text.Encoding.GetEncoding("GB2312")))
{
while ((strLine = reader.ReadLine()) != null)
{
csvReset = strLine.Split(',', '[', ']');
if (csvReset.Length != 5 && csvReset[0] == "")
{
continue;
}
if (string.IsNullOrEmpty(csvReset[4]) || string.IsNullOrWhiteSpace(csvReset[4]))
{
break; // 空地址跳出读取
}
PlcAddress = csvReset[4];
AxleLog axle = new AxleLog();
axle.m_AxleDscribe = csvReset[0] + csvReset[1];
axle.m_AxleLocation = csvReset[3];
axle.m_AxleAddress = PlcAddress;
axleLog.Add(axle);
if (isExits)
{
string Value = CommonMethods.plcDevices[0].ReadFloat(PlcAddress).ToString();
IniConfigHelper.WriteIniData(axle.m_AxleDscribe, axle.m_AxleLocation, Value, Path.Combine(configFolderPath, "Motor_GunBiaoAxle.ini"));
}
}
reader.Close();
reader.Dispose();
}
break;
case 2://本机电机位置设定值motor
IniConfigHelper.CreateIniFile(configFolderPath, "Motor_GunBiaoMotor.ini");
if (!File.Exists(Path.Combine(configFolderPath, "Motor_GunBiaoMotor.ini")))//判断ini文件是否存在
{
isExits = true;
}
using (StreamReader reader = new StreamReader(Path.Combine(configFolderPath, "Motor_GunBiaoMotor.csv"), System.Text.Encoding.GetEncoding("GB2312")))
{
while ((strLine = reader.ReadLine()) != null)
{
csvReset = strLine.Split(',', '[', ']');
if (csvReset.Length != 5 && csvReset[0] == "")
{
continue;
}
if (string.IsNullOrEmpty(csvReset[4]) || string.IsNullOrWhiteSpace(csvReset[4]))
{
break; // 空地址跳出读取
}
PlcAddress = csvReset[4];
MotorLog motor = new MotorLog();
motor.m_MotorDscribe = csvReset[0] + csvReset[1];
motor.m_MotorLocation = csvReset[3];
motor.m_MotorAddress = PlcAddress;
motorLog.Add(motor);
if (isExits)
{
string Value = CommonMethods.plcDevices[0].ReadFloat(PlcAddress).ToString();
IniConfigHelper.WriteIniData(motor.m_MotorDscribe, motor.m_MotorLocation, Value, Path.Combine(configFolderPath, "Motor_GunBiaoMotor.ini"));
}
}
reader.Close();
reader.Dispose();
}
break;
default: break;
}
}
catch (Exception ex)
{
axleLog = null;
motorLog = null;
LogHelper.Instance.WriteError($"轴/电机位置读取配置文件错误:{ex}", "SysErrorLog");
}
}
/// <summary>轴/电机对象集合
///
/// </summary>
private static List<MotorLog> motorLog = new List<MotorLog>();
private static List<AxleLog> axleLog = new List<AxleLog>();
private static Stopwatch swtest = new Stopwatch();
/// <summary>
/// 监控轴位置变化
/// </summary>
public void ShowAxleEven_Run()
{
try
{
while (true)
{
if (CommonMethods.plcDevices[0] != null && CommonMethods.plcDevices[0].IsConnected)
{
short nowPLCstate = CommonMethods.plcDevices[0].ReadInt16("D10");
if (nowPLCstate != 1)
{
if (axleLog.Count < 1 || motorLog.Count < 1)
{
Thread.Sleep(1500);
ReadAxleCSV(1, ref axleLog, ref motorLog);//轴位置csv文件不存在,out axlelog=null,导致下次判断axlelog.Count报错(未将对象引用设置到对象实例)
Thread.Sleep(1500);
}
else
{
try
{
// 第二种写法一次读出来
swtest.Restart();
JYResult<byte[]> resByte = CommonMethods.plcDevices[0].ReadValue<JYResult<byte[]>>($"{axleLog[0].m_AxleAddress}", DataType.ArrByte, Convert.ToUInt16(axleLog.Count * 4));
swtest.Stop();
long tempswt = swtest.ElapsedMilliseconds;
swtest.Restart();
if (resByte != null && resByte.IsSuccess && resByte.Content != null)
{
string AxleUpLocationOld;
string AxleUpLocationNew;
for (int i = 0; i < axleLog.Count; i++)
{
double NewCurrent = FloatLib.GetFloatFromByteArray(resByte.Content, i * 4); //D23000 起
AxleUpLocationOld = IniConfigHelper.ReadIniData(axleLog[i].m_AxleDscribe, axleLog[i].m_AxleLocation, "0", Path.Combine(configFolderPath, "Motor_GunBiaoAxle.ini"));
AxleUpLocationNew = Math.Round(NewCurrent, 2).ToString();
if (AxleUpLocationNew != AxleUpLocationOld)
{
string AlterTime = DateTime.Now.ToString("yyyy-MM-dd_HH:mm:ss.fff");
//日期时间,电机描述,位置描述,位置修改前,当前位置
LogHelper.PrintMotorLog.LogInfo(AlterTime, axleLog[i].m_AxleDscribe, axleLog[i].m_AxleLocation, AxleUpLocationOld, AxleUpLocationNew);
IniConfigHelper.WriteIniData(axleLog[i].m_AxleDscribe, axleLog[i].m_AxleLocation, AxleUpLocationNew, Path.Combine(configFolderPath, "Motor_GunBiaoAxle.ini"));
}
}
}
swtest.Stop();
tempswt = swtest.ElapsedMilliseconds;
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"轴位置监控线程错误:{ex}", "SysErrorLog");
}
}
}
}
else { Thread.Sleep(5000); }
Thread.Sleep(1000);
}
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"轴位置监控线程错误:{ex}", "SysErrorLog");
}
}
/// <summary>
/// 监控电机位置变化
/// </summary>
public void ShowMotorEven_Run()
{
try
{
while (true)
{
if (CommonMethods.plcDevices[0] != null && CommonMethods.plcDevices[0].IsConnected)
{
short nowPLCstate = CommonMethods.plcDevices[0].ReadInt16("D10");
if (nowPLCstate != 1)
{
if (axleLog.Count < 1 || motorLog.Count < 1)
{
Thread.Sleep(3000);
ReadAxleCSV(2, ref axleLog, ref motorLog);//电机位置csv文件不存在,out axlelog=null,导致下次判断axlelog.Count报错(未将对象引用设置到对象实例)
Thread.Sleep(1500);
}
else
{
try
{
// 第二种写法一次读出来
swtest.Restart();
JYResult<byte[]> resByte = CommonMethods.plcDevices[0].ReadValue<JYResult<byte[]>>($"{motorLog[0].m_MotorAddress}", DataType.ArrByte, Convert.ToUInt16(motorLog.Count * 4));
swtest.Stop();
long tempswt = swtest.ElapsedMilliseconds;
swtest.Restart();
if (resByte != null && resByte.IsSuccess && resByte.Content != null)
{
string MotorUpLocationOld;
string MotorUpLocationNew;
for (int i = 0; i < motorLog.Count; i++)
{
double NewCurrent = FloatLib.GetFloatFromByteArray(resByte.Content, i * 4); //D23000 起
MotorUpLocationOld = IniConfigHelper.ReadIniData(motorLog[i].m_MotorDscribe, motorLog[i].m_MotorLocation, "0", Path.Combine(configFolderPath, "Motor_GunBiaoAxle.ini"));
MotorUpLocationNew = Math.Round(NewCurrent, 2).ToString();
if (MotorUpLocationNew != MotorUpLocationOld)
{
string AlterTime = DateTime.Now.ToString("yyyy-MM-dd_HH:mm:ss.fff");
//日期时间,电机描述,位置描述,位置修改前,当前位置
LogHelper.PrintMotorLog.LogInfo(AlterTime, motorLog[i].m_MotorDscribe, motorLog[i].m_MotorLocation, MotorUpLocationOld, MotorUpLocationNew);
IniConfigHelper.WriteIniData(motorLog[i].m_MotorDscribe, motorLog[i].m_MotorLocation, MotorUpLocationNew, Path.Combine(configFolderPath, "Motor_GunBiaoAxle.ini"));
}
}
}
swtest.Stop();
tempswt = swtest.ElapsedMilliseconds;
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"电机位置监控线程错误:{ex}", "SysErrorLog");
}
}
}
}
else { Thread.Sleep(5000); }
Thread.Sleep(1000);
}
}
catch (Exception ex)
{
LogHelper.Instance.WriteError($"电机位置监控线程错误:{ex}", "SysErrorLog");
}
}
#endregion
}
}