Files
FATrace/FATrace.WPLApp/Services/DataServices.cs
2026-01-29 22:15:34 +08:00

774 lines
31 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 AutoMapper;
using FATrace.Model;
using FATrace.WPLApp.Events;
using FATrace.WPLApp.ModelDto;
using FATrace.WPLApp.Models;
using HslCommunication;
using HslCommunication.Profinet.Keyence;
using Prism.Events;
using Prism.Mvvm;
using System.Collections.Concurrent;
using System.Windows;
using ComConfigHelper = FATrace.Com.ConfigHelper;
namespace FATrace.WPLApp.Services
{
/// <summary>
/// 数据服务
/// 产线PLC数据交互的服务
/// </summary>
public class DataServices : BindableBase, IDisposable
{
public DataServices(ILogService logService, IFreeSql freeSql, IEventAggregator eventAggregator, IMapper mapper, SysRunService sysRunService, CsvServices csvServices)
{
LogService = logService;
FreeSql = freeSql;
EventAggregator = eventAggregator;
Mapper = mapper;
SysRunService = sysRunService;
CsvServices = csvServices;
LineSglModel = new LineSglModel();
LineSglModel.WeightScanCodeHandle += LineSglModel_WeightScanCodeHandle;
LineSglModel.BoxSprayCodeReqHandle += LineSglModel_BoxSprayCodeReqHandle;
LineSglModel.BoxScanCodeReqHandle += LineSglModel_BoxScanCodeReqHandle;
PLCLinkInitial();
StartPlcScan();
//var DD= RevData("DYG05030013,20250923,802,3,01,0001,");
//var dd1= RevData("DYG05030013,251111,10193,6,01,3");
//var dd2 = RevData("DYG05030013,251111,2116,6,01,3");
}
/// <summary>
///外箱喷码请求
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void LineSglModel_BoxSprayCodeReqHandle(object? sender, string e)
{
//首先复位PLC信号
var SetValueResult = KeyencePlcMcNet!.Write("D1100", (Int16)0);
if (!SetValueResult.IsSuccess)
{
//写入失败,重新写入
LogService.Warn("外箱喷码-复位PLC信号失败-执行两次写入0");
KeyencePlcMcNet!.Write("D1100", (Int16)0);
KeyencePlcMcNet!.Write("D1100", (Int16)0);
}
//获取箱子喷码的数据+A
var ReqData = FreeSql.Select<LineTempCode>()
.OrderByDescending(a => a.Id)
.Limit(1)
.ToList();
//无数据再重试一次
if (ReqData.Count <= 0)
{
try
{
Thread.Sleep(50);
}
catch
{
}
ReqData = FreeSql.Select<LineTempCode>()
.OrderByDescending(a => a.Id)
.Limit(1)
.ToList();
LogService.Warn("外箱喷码-不存在请求的数据-重试一次");
}
if (ReqData.Count > 0)
{
var CodeItem = ReqData.FirstOrDefault();
var BoxSprayCodeSource = CodeItem!.Code + ",A";
var BoxSprayCodeRev = RevData(BoxSprayCodeSource);
BoxSprayCode = BoxSprayCodeSource;
var Result = KeyencePlcMcNet.Write("D1150", BoxSprayCodeRev);
if (!Result.IsSuccess)
{
//写入失败,重新写入
LogService.Warn("外箱喷码-写入条码 D1150 PLC信号失败-执行两次写入条码");
KeyencePlcMcNet.Write("D1150", BoxSprayCodeRev);
}
Console.WriteLine($"外箱喷码:{BoxSprayCodeSource}-发送OK");
}
else
{
//不存在请求的数据,报错
KeyencePlcMcNet.Write("D1102", (Int16)1);
Console.WriteLine($"外箱喷码:不存在请求的数据");
AddAlarm("外箱喷码", "不存在请求的数据");
LogService.Warn("外箱喷码-不存在请求的数据");
}
Task.Run(async () =>
{
await Task.Delay(1000).ConfigureAwait(false);
var Data = KeyencePlcMcNet!.Write("D1102", (Int16)0);
if (!Data.IsSuccess)
{
//写入失败,重新写入
LogService.Warn("外箱喷码-复位D1102PLC信号失败-执行两次写入0");
KeyencePlcMcNet!.Write("D1102", (Int16)0);
KeyencePlcMcNet!.Write("D1102", (Int16)0);
}
//KeyencePlcMcNet.Write("D1150", new Int16[30]);
});
}
/// <summary>
/// 外箱扫描码请求
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <exception cref="NotImplementedException"></exception>
private void LineSglModel_BoxScanCodeReqHandle(object? sender, string e)
{
//首先复位PLC信号
var SetValueResult = KeyencePlcMcNet!.Write("D1200", (Int16)0);
if (!SetValueResult.IsSuccess)
{
//写入失败,重新写入
LogService.Warn("外箱扫描码请求-复位PLC信号失败-执行两次写入0");
KeyencePlcMcNet!.Write("D1200", (Int16)0);
KeyencePlcMcNet!.Write("D1200", (Int16)0);
}
string BoxScanCode = string.Empty;
BoxScanCode = this.BoxScanCode;
if (!string.IsNullOrEmpty(BoxScanCode))
{
var IsExist = FreeSql.Select<RawProUse>().Where(a => a.BoxCode == BoxScanCode);
//var IsExist = FreeSql.Select<RawProUse>().Where(a => a.BoxCode!.Contains(BoxScanCode));// 内包和外包一样的条码测试用 ???????????????
if (IsExist.Count() > 0)
{
//存在条码数据 OK返回PLC结果
var DataResult = KeyencePlcMcNet!.Write("D1210", (Int16)1);
if (!DataResult.IsSuccess)
{
//写入失败,重新写入
LogService.Warn("外箱扫描码请求-置位D1210PLC信号失败-执行两次写入1");
KeyencePlcMcNet!.Write("D1210", (Int16)1);
KeyencePlcMcNet!.Write("D1210", (Int16)1);
}
Console.WriteLine($"外箱扫描码:{BoxScanCode}-存在找到");
// 加入队列
//EnqueueMessage(WeightScanCode);
LogService.Info($"外箱扫描码:{BoxScanCode}");
//删除临时的队列条码数据
var DeleteResult = FreeSql.Delete<LineTempCode>()
.Where(p => BoxScanCode.Contains(p.Code!))
.ExecuteAffrows();
if (DeleteResult > 0)
{
Console.WriteLine($"外箱扫描码:{BoxScanCode}-删除临时队列数据成功");
LogService.Info($"外箱扫描码:{BoxScanCode}-删除临时队列数据成功");
try { EventAggregator?.GetEvent<DashboardRefreshEvent>()?.Publish(true); } catch { }
}
else
{
Console.WriteLine($"外箱扫描码:{BoxScanCode}-删除临时队列数据失败");
LogService.Info($"外箱扫描码:{BoxScanCode}-删除临时队列数据失败");
AddAlarm("外箱扫描", $"{BoxScanCode}-删除临时队列数据失败");
try { EventAggregator?.GetEvent<DashboardRefreshEvent>()?.Publish(true); } catch { }
}
var UpdatedResult = FreeSql.Update<RawProUse>()
.Set(p => p.OutTime, DateTime.Now)
.Where(p => p.BoxCode == BoxScanCode)//外箱二维码就是外箱扫描码
.ExecuteUpdated();
if (UpdatedResult.Count() > 0)
{
var Data = CsvServices.ExportSingle(Mapper.Map<RawProUserCsvDto>(UpdatedResult.First()), true);
if (Data != null && !string.IsNullOrEmpty(Data))
{
Console.WriteLine($"外箱扫描码:{BoxScanCode} CSV文件生成");
}
else
{
Console.WriteLine($"外箱扫描码:{BoxScanCode} CSV文件失败");
}
Console.WriteLine($"外箱扫描码:{BoxScanCode}更新时间成功");
LogService.Info($"外箱扫描码:{BoxScanCode}更新时间成功");
}
else
{
Console.WriteLine($"外箱扫描码:{BoxScanCode}更新时间失败");
LogService.Warn($"外箱扫描码:{BoxScanCode}更新时间失败");
AddAlarm("外箱扫描", $"{BoxScanCode}更新时间失败");
}
}
else
{
//不存在条码数据 NG返回PLC结果报警
KeyencePlcMcNet!.Write("D1210", (Int16)2);
Console.WriteLine($"外箱扫描码:{BoxScanCode}-未发现外箱扫码数据在数据库中");
LogService.Warn($"外箱扫描码:{BoxScanCode}-未发现外箱扫码数据在数据库中");
AddAlarm("外箱扫描", $"{BoxScanCode}-未发现外箱扫码数据在数据库中");
}
}
else
{
Console.WriteLine($"外箱扫描码为空");
LogService.Warn("外箱扫描码为空");
AddAlarm("外箱扫描", "外箱扫描码为空");
}
Task.Run(async () =>
{
await Task.Delay(1200).ConfigureAwait(false);
var DataResult = KeyencePlcMcNet!.Write("D1210", (Int16)0);
if (!DataResult.IsSuccess)
{
//写入失败,重新写入
LogService.Warn("外箱扫描码请求-复位D1210PLC信号失败-执行两次写入0");
KeyencePlcMcNet!.Write("D1210", (Int16)0);
KeyencePlcMcNet!.Write("D1210", (Int16)0);
}
KeyencePlcMcNet.Write("D1250", new Int16[30]);
});
}
/// <summary>
/// 称重 内包扫描码请求数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <exception cref="NotImplementedException"></exception>
private void LineSglModel_WeightScanCodeHandle(object? sender, string e)
{
//首先复位PLC信号
var SetValueResult = KeyencePlcMcNet!.Write("D1000", (Int16)0);
if (!SetValueResult.IsSuccess)
{
//写入失败,重新写入
LogService.Warn("称重扫描码-复位PLC信号失败-执行两次写入0");
KeyencePlcMcNet!.Write("D1000", (Int16)0);
KeyencePlcMcNet!.Write("D1000", (Int16)0);
}
if (!string.IsNullOrEmpty(WeightScanCode))
{
var IsExist = FreeSql.Select<RawProUse>().Where(a => a.InBagCode == WeightScanCode);
if (IsExist.Count() > 0)
{
//存在条码数据 OK返回PLC结果
var SetValueResult1 = KeyencePlcMcNet!.Write("D1010", (Int16)1);
if (!SetValueResult1.IsSuccess)
{
//写入失败,重新写入
LogService.Warn("称重扫描码-置位数据D1010 PLC信号失败-执行两次写入1");
KeyencePlcMcNet!.Write("D1010", (Int16)1);
KeyencePlcMcNet!.Write("D1010", (Int16)1);
}
Console.WriteLine($"称重扫描码:{WeightScanCode}");
//// 加入队列
//EnqueueMessage(WeightScanCode);
LogService.Info($"称重扫描码:{WeightScanCode}");
try
{
var delAff = FreeSql.Delete<LineTempCode>()
.Where(p => p.Id > 0)
.ExecuteAffrows();
var insAff = FreeSql.Insert<LineTempCode>(new LineTempCode()
{
Code = WeightScanCode
}).ExecuteAffrows();
if (insAff <= 0)
{
LogService.Warn($"称重扫描码:{WeightScanCode} 写入临时表 LineTempCode 失败(affrows={insAff})delAff={delAff}");
}
}
catch (Exception ex)
{
LogService.Error($"称重扫描码:{WeightScanCode} 写入临时表 LineTempCode 异常: {ex}");
}
try
{
EventAggregator?.GetEvent<DashboardRefreshEvent>()?.Publish(true);
}
catch
{
}
var Result = FreeSql.Update<RawProUse>()
.Set(p => p.WeightScanTime, DateTime.Now)
.Where(p => p.InBagCode == WeightScanCode)//内箱二维码就是称重扫描码
.ExecuteAffrows();
if (Result > 0)
{
Console.WriteLine($"称重扫描码:{WeightScanCode}更新时间成功");
LogService.Info($"称重扫描码:{WeightScanCode}更新时间成功");
}
else
{
Console.WriteLine($"称重扫描码:{WeightScanCode}更新时间失败");
LogService.Warn($"称重扫描码:{WeightScanCode}更新时间失败");
AddAlarm("称重扫描", $"{WeightScanCode}更新时间失败");
}
}
else
{
//不存在条码数据 NG返回PLC结果报警
KeyencePlcMcNet!.Write("D1010", (Int16)2);
Console.WriteLine($"称重扫描码:{WeightScanCode}-未发现内包扫码数据在数据库中");
LogService.Warn($"称重扫描码:{WeightScanCode}-未发现内包扫码数据在数据库中");
AddAlarm("称重扫描", $"{WeightScanCode}-未发现内包扫码数据在数据库中");
}
Task.Run(async () =>
{
await Task.Delay(1200).ConfigureAwait(false);
//KeyencePlcMcNet!.Write("D1010", (Int16)0);
var SetValueResult2 = KeyencePlcMcNet!.Write("D1010", (Int16)0);
if (!SetValueResult2.IsSuccess)
{
//写入失败,重新写入
LogService.Warn("称重扫描码-复位数据D1010 PLC信号失败-执行两次写入0");
KeyencePlcMcNet!.Write("D1010", (Int16)0);
}
KeyencePlcMcNet.Write("D1050", new Int16[30]);
});
}
else
{
Console.WriteLine($"称重扫描码为空");
LogService.Warn("称重扫描码为空");
AddAlarm("称重扫描", "称重扫描码为空");
}
}
public ILogService LogService { get; }
public IFreeSql FreeSql { get; }
public IEventAggregator EventAggregator { get; }
public IMapper Mapper { get; }
public SysRunService SysRunService { get; }
public CsvServices CsvServices { get; }
private bool _plcConnected;
public bool PlcConnected
{
get { return _plcConnected; }
private set { _plcConnected = value; RaisePropertyChanged(); }
}
/// <summary>
/// 基恩士通信组件
/// </summary>
private KeyenceMcNet KeyencePlcMcNet { get; set; } = null;
private string _WeightScanCode;
/// <summary>
/// 称重扫描码
/// </summary>
public string WeightScanCode
{
get { return _WeightScanCode; }
set { _WeightScanCode = value; RaisePropertyChanged(); }
}
private string _BoxScanCode;
/// <summary>
/// 外箱喷码扫码数据
/// </summary>
public string BoxScanCode
{
get { return _BoxScanCode; }
set { _BoxScanCode = value; RaisePropertyChanged(); }
}
private string _boxSprayCode;
/// <summary>
/// 最近一次下发给 PLC 的外箱喷码数据(源字符串,不做 RevData 对调处理)
/// </summary>
public string BoxSprayCode
{
get { return _boxSprayCode; }
set { _boxSprayCode = value; RaisePropertyChanged(); }
}
// 扫描控制
private CancellationTokenSource? _plcScanCts;
private Task? _plcScanTask;
private volatile bool _isScanning = false;
public bool IsScanning => _isScanning;
private bool _disposed = false;
/// <summary>
/// 产线信号模型
/// </summary>
public LineSglModel LineSglModel { get; set; }
/// <summary>
/// PLC通信初始化
/// </summary>
/// <param name="PLCIp"></param>
/// <param name="Port"></param>
private void PLCLinkInitial()
{
try
{
// 读取 PLC 配置(大小写敏感,采用公共 ConfigHelper 并提供默认值)
string PLCIP = ComConfigHelper.GetStringOrDefault("PLCIP", "192.0.1.10");
int Port = ComConfigHelper.GetIntOrDefault("PLCPort", 5000);
try { SysRunService.PlcIp = PLCIP; SysRunService.PlcPort = Port; } catch { }
//PLC通信的连接
KeyencePlcMcNet = new KeyenceMcNet();
KeyencePlcMcNet.IpAddress = PLCIP;
KeyencePlcMcNet.Port = Port;
KeyencePlcMcNet.ConnectClose();
KeyencePlcMcNet.ConnectTimeOut = 3000; // 连接3秒超时
OperateResult connect = KeyencePlcMcNet.ConnectServer();
if (connect.IsSuccess)//初始连接状态的显示判断
{
Console.WriteLine($"PLC-连接 OK");
LogService.Error($"PLC-连接 OK");
PlcConnected = true;
try { SysRunService.PlcLinkState = true; SysRunService.SysRunState.ComState = 1; SysRunService.SysRunState.ComMsg = "正常"; } catch { }
}
else
{
MessageBox.Show(connect.Message + Environment.NewLine + "ErrorCode: " + connect.ErrorCode);
PlcConnected = false;
try { SysRunService.PlcLinkState = false; SysRunService.SysRunState.ComState = 2; SysRunService.SysRunState.ComMsg = "连接失败"; } catch { }
}
}
catch (Exception ex)
{
LogService.Error(String.Format("ErrSource : {0} ErrMsg : {1}", ex.StackTrace.ToString(), ex.Message.ToString()));
//insertLogToDBDelegate.BeginInvoke(1, "UpdateUIMethod异常", ex.Message.ToString() + ex.StackTrace.Substring(ex.StackTrace.Length - 40, 40), null, null);
PlcConnected = false;
try { SysRunService.PlcLinkState = false; SysRunService.SysRunState.ComState = 2; SysRunService.SysRunState.ComMsg = "异常"; } catch { }
}
}
/// <summary>
/// 启动PLC扫描。若已在扫描则忽略重复启动。
/// </summary>
/// <param name="scanPeriod">扫描周期,若为 null 则读取 App.config 的 PLCScan毫秒默认600ms</param>
/// <param name="externalToken">可选:外部取消令牌,用于联动取消</param>
public void StartPlcScan(TimeSpan? scanPeriod = null, CancellationToken externalToken = default)
{
if (_isScanning) return;
var period = scanPeriod ?? ComConfigHelper.GetTimeSpanOrDefault("PLCScan", TimeSpan.FromMilliseconds(600));
_plcScanCts = CancellationTokenSource.CreateLinkedTokenSource(externalToken);
var token = _plcScanCts.Token;
_isScanning = true;
try { SysRunService.PlcScanState = 1; } catch { }
_plcScanTask = Task.Run(() => PlcScanLoopAsync(period, token), token);
_plcScanTask.ContinueWith(t =>
{
try
{
if (t.IsFaulted)
{
try { SysRunService.PlcScanState = 2; } catch { }
try { LogService.Error($"PLC扫描任务异常退出: {t.Exception}"); } catch { }
}
else if (t.IsCanceled)
{
try { SysRunService.PlcScanState = 0; } catch { }
}
else
{
try { SysRunService.PlcScanState = 0; } catch { }
}
}
catch
{
}
}, TaskScheduler.Default);
}
/// <summary>
/// 停止PLC扫描等待后台任务结束。
/// </summary>
public async Task StopPlcScanAsync()
{
try
{
if (_plcScanCts != null)
{
_plcScanCts.Cancel();
}
if (_plcScanTask != null)
{
try { await _plcScanTask.ConfigureAwait(false); } catch { /* ignore */ }
}
}
finally
{
_isScanning = false;
_plcScanTask = null;
_plcScanCts?.Dispose();
_plcScanCts = null;
try { SysRunService.PlcScanState = 0; } catch { }
}
}
/// <summary>
/// 称重扫描条码OperateResult结果
/// </summary>
private OperateResult<string> OperateResultWeightScanCode { get; set; }
/// <summary>
/// 称重扫描条码OK信号
/// </summary>
private OperateResult<Int16> OperateResultWeightScanSgl { get; set; }
/// <summary>
/// 外箱喷码请求信号
/// </summary>
private OperateResult<Int16> OperateResultBoxSprayCodeReqSgl { get; set; }
/// <summary>
/// 外箱扫码条码OperateResult结果
/// </summary>
private OperateResult<string> OperateResultBoxScanCode { get; set; }
/// <summary>
/// 外箱扫码请求信号
/// </summary>
private OperateResult<Int16> OperateResultBoxScanSgl { get; set; }
/// <summary>
/// 扫描循环按周期轮询PLC寄存器并更新模型。
/// - 读取配置项 Addr_WeightPhotoEnable默认 M100为布尔量
/// - 读失败时尝试重连一次
/// </summary>
private async Task PlcScanLoopAsync(TimeSpan period, CancellationToken token)
{
string addrWeight = ComConfigHelper.GetStringOrDefault("Addr_WeightPhotoEnable", "M100");
bool? lastWeight = null;
while (!token.IsCancellationRequested)
{
try
{
if (KeyencePlcMcNet == null)
{
PLCLinkInitial();
}
//内包扫码
OperateResultWeightScanCode = KeyencePlcMcNet!.ReadString("D1050", 20);
if (OperateResultWeightScanCode.IsSuccess)
{
WeightScanCode = RevData(OperateResultWeightScanCode.Content).Replace("\r", "").Replace("\n", "").Trim();
}
OperateResultWeightScanSgl = KeyencePlcMcNet!.ReadInt16("D1000");
if (OperateResultWeightScanSgl.IsSuccess)
{
LineSglModel.WeightScanCodeEnable = OperateResultWeightScanSgl.Content;
}
//外箱喷码
OperateResultBoxSprayCodeReqSgl = KeyencePlcMcNet!.ReadInt16("D1100");
if (OperateResultBoxSprayCodeReqSgl.IsSuccess)
{
LineSglModel.BoxSprayCodeReqEnable = OperateResultBoxSprayCodeReqSgl.Content;
}
//外箱扫码
OperateResultBoxScanCode = KeyencePlcMcNet!.ReadString("D1250", 20);
if (OperateResultBoxScanCode.IsSuccess)
{
BoxScanCode = RevData(OperateResultBoxScanCode.Content).Replace("\r", "").Replace("\n", "").Trim();
//BoxScanCode = OperateResultBoxScanCode.Content.Replace("\r", "").Replace("\n", "");
}
OperateResultBoxScanSgl = KeyencePlcMcNet!.ReadInt16("D1200");
if (OperateResultBoxScanSgl.IsSuccess)
{
LineSglModel.BoxScanCodeEnable = OperateResultBoxScanSgl.Content;
PlcConnected = true;
try { SysRunService.PlcLinkState = true; SysRunService.SysRunState.ComState = 1; SysRunService.SysRunState.ComMsg = "正常"; } catch { }
}
else
{
PlcConnected = false;
try { SysRunService.PlcLinkState = false; SysRunService.SysRunState.ComState = 2; SysRunService.SysRunState.ComMsg = "连接失败"; } catch { }
}
}
catch (Exception ex)
{
LogService.Error($"PLC 扫描异常 Exception: {ex.ToString()}");
// 这里属于循环内部异常:循环仍会继续;
// 但若后续由于未捕获异常导致扫描任务退出StartPlcScan 的 ContinueWith 也会做最终状态处理。
}
finally
{
try
{
await Task.Delay(period, token).ConfigureAwait(false);
}
catch (OperationCanceledException ex)
{
// 正常停止扫描时会触发取消,这里不应记录为错误。
// 不允许从 finally 中 break/return
// 这里吞掉异常,循环将在下一次 while 判断时依据 token 自动退出
}
}
}
_isScanning = false;
// 退出循环:如果是正常取消,则 StopPlcScanAsync 会把状态置为停止;
// 若是外部未走 StopPlcScanAsync而 token 已取消,也归为停止。
try
{
if (token.IsCancellationRequested) SysRunService.PlcScanState = 0;
}
catch { }
}
/// <summary>
/// 尝试重连 PLC快速一次
/// </summary>
private async Task TryReconnectAsync(CancellationToken token)
{
try
{
if (KeyencePlcMcNet == null) { PLCLinkInitial(); return; }
KeyencePlcMcNet.ConnectClose();
await Task.Delay(100, token).ConfigureAwait(false);
KeyencePlcMcNet.ConnectTimeOut = 3000;
var ret = KeyencePlcMcNet.ConnectServer();
if (!ret.IsSuccess)
{
LogService.Warn($"PLC重连失败: {ret.Message} (Code: {ret.ErrorCode})");
PlcConnected = false;
try { SysRunService.PlcLinkState = false; SysRunService.SysRunState.ComState = 2; SysRunService.SysRunState.ComMsg = "异常"; } catch { }
}
else { PlcConnected = true; try { SysRunService.PlcLinkState = true; SysRunService.SysRunState.ComState = 1; SysRunService.SysRunState.ComMsg = "正常"; } catch { } }
}
catch (Exception ex)
{
LogService.Error($"PLC重连异常: {ex.Message}");
PlcConnected = false;
try { SysRunService.PlcLinkState = false; SysRunService.SysRunState.ComState = 2; SysRunService.SysRunState.ComMsg = "异常"; } catch { }
}
}
/// <summary>
/// 释放资源确保扫描停止并断开PLC连接。
/// </summary>
public void Dispose()
{
if (_disposed) return;
_disposed = true;
try
{
// 停止扫描
try { StopPlcScanAsync().GetAwaiter().GetResult(); } catch { }
// 解除事件订阅(当前未订阅自定义事件,保留占位以便后续扩展)
// try { /* no event to unsubscribe */ } catch { }
// 关闭PLC连接
try { KeyencePlcMcNet?.ConnectClose(); } catch { }
}
finally
{
KeyencePlcMcNet = null;
}
}
/// <summary>
/// 把字符串对调
/// </summary>
public string RevData(string Code)
{
// 需求PLC 字符串按“字”(2字节)进行高低字节对调,导致 ABCDEF -> BADCFE
// 纠正方式:按两个字符一组交换顺序,奇数长度保留最后一个字符
if (string.IsNullOrEmpty(Code)) return string.Empty;
// 去掉读取中可能包含的 '\0' 空字符
var src = Code.Replace("\0", string.Empty);
var sb = new System.Text.StringBuilder(src.Length);
for (int i = 0; i < src.Length; i += 2)
{
if (i + 1 < src.Length)
{
sb.Append(src[i + 1]);
sb.Append(src[i]);
}
else
{
// 奇数长度,最后一个字符原样保留
//sb.Append((char)0x0);
sb.Append('\0');
sb.Append(src[i]);
}
}
return sb.ToString();
}
/// <summary>
/// 写入历史报警
/// </summary>
private void AddAlarm(string category, string message)
{
try
{
FreeSql.Insert(new HistoryAlarm
{
Category = category,
Message = message,
CreateTime = DateTime.Now
}).ExecuteAffrows();
}
catch (Exception ex)
{
LogService.Error($"写入历史报警失败: {ex.Message}");
}
}
}
}