using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Messaging; using GalaSoft.MvvmLight; using Microsoft.Extensions.DependencyInjection; using NVelocity.Runtime.Directive; using Serilog; using SlnMesnac.Common; using SlnMesnac.Config; using SlnMesnac.Model.domain; using SlnMesnac.Model.dto; using SlnMesnac.Model.Enum; using SlnMesnac.Repository; using SlnMesnac.Repository.service; using SlnMesnac.Repository.service.Impl; using SlnMesnac.Rfid; using SlnMesnac.Rfid.Enum; using SlnMesnac.Serilog; using SlnMesnac.TouchSocket; using SlnMesnac.WPF.Attribute; using SlnMesnac.WPF.Model; using SqlSugar; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using System.Windows.Markup; using System.Windows.Threading; using System.Xml.Serialization; using TouchSocket.Core; using static Microsoft.WindowsAPICodePack.Shell.PropertySystem.SystemProperties.System; using Task = System.Threading.Tasks.Task; namespace SlnMesnac.WPF.ViewModel.IndexPage { [RegisterAsSingletonAttribute] public class ProductionLineViewModel : ViewModelBase { #region 参数定义 private static StringChange _StringChange; private String SerialNo = ""; private SerilogHelper _logger; //private ISqlSugarClient? sqlSugarClient; //容器里面的读写器集合 public List rfidList; private AppConfig appConfig; private MeshttpClient meshttpClient; public TcpServer _TcpServer; private DispatcherTimer _timer; private Dictionary _inventoryTimers = new Dictionary(); private ObservableCollection _rfidHistoryRecords = new ObservableCollection(); private RealReadDataImpl databaseService = RealReadDataImpl.Instance; private System.Threading.Timer ReReadTimer; private bool IsVerify = false; private int WriteTime = 0; private string LastWrite; private string LastRFIDEPC; private CancellationTokenSource? _verifyCts; private CancellationTokenSource? _writeCts; #endregion #region 关联属性 public ObservableCollection RFIDHistoryRecords { get { return _rfidHistoryRecords; } set { _rfidHistoryRecords = value; RaisePropertyChanged(() => RFIDHistoryRecords); } } ChangeTypeViewModel ChangeTypeView; private ObservableCollection _Deviceinfo = new ObservableCollection(); public ObservableCollection Deviceinfo { get { return _Deviceinfo; } set { _Deviceinfo = value; RaisePropertyChanged(() => Deviceinfo); } } /// /// 日期时间 /// private DateTime _currentDateTime; public DateTime CurrentDateTime { get => _currentDateTime; set { if (_currentDateTime != value) { _currentDateTime = value; RaisePropertyChanged(() => CurrentDateTime); } } } /// /// 上一次写入状态 /// private string _lastWriteState; public string LastWriteState { get => _lastWriteState; set { if (_lastWriteState != value) { _lastWriteState = value; RaisePropertyChanged(() => LastWriteState); } } } /// /// 当前状态 空闲 盘点中 写入中 /// private string _CurrentState = "空闲"; public string CurrentState { get => _CurrentState; set { if (_CurrentState != value) { _CurrentState = value; RaisePropertyChanged(() => CurrentState); } } } #endregion #region 构造函数 public ProductionLineViewModel() { ChangeTypeView = App.ServiceProvider.GetService(); // 构造函数里注册 WeakReferenceMessenger.Default.Register(this, RefreshOrderNo); WeakReferenceMessenger.Default.Register(this, "Cancel", StopMessage); _StringChange = App.ServiceProvider.GetService(); _logger = App.ServiceProvider.GetService(); appConfig = App.ServiceProvider.GetService(); //sqlSugarClient = App.ServiceProvider.GetService(); _TcpServer = App.ServiceProvider.GetRequiredService(); rfidList = App.ServiceProvider.GetRequiredService>(); rfidList.ForEach(rfid => { rfid._Action += RecvIdentifyData_Instance; //rfid._RefreshLogMessageAction += RefreshLogMessage; }); LoadDeviceInfo(); StartCheckStatus(); //GetRFIDHistoryRecords(); _currentDateTime = DateTime.Now; _timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) // 每秒更新一次 }; _timer.Tick += (s, e) => { CurrentDateTime = DateTime.Now; }; _timer.Start(); Log.Information("RFID输送带系统启动"); } #endregion #region 核心写入算法 /// /// 接收到连续盘点标签返回 /// /// /// private async void RecvIdentifyData_Instance(string iCombineId, List tagInfos) { try { _writeCts?.Cancel(); var rfidInfo = rfidList.FirstOrDefault(x => x.deviceid == iCombineId); var deviceInfo = Deviceinfo.FirstOrDefault(x => x.Deviceid == iCombineId); var deviceConfig = appConfig.deviceInfoConfig.FirstOrDefault(x => x.Deviceid == iCombineId); //初次写入 if (!IsVerify) { //写入前等待标签稳定 if (!IsVerify) { await Task.Delay(deviceInfo.WriteDelaySet ?? 2000); } //验证是否已获取订单信息 if (string.IsNullOrEmpty(deviceInfo.OrderNo)) { MessageBox.Show("请先获取MES订单号!", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } //查询数据库是否已存在记录 string epcascii = Encoding.ASCII.GetString(tagInfos[0].EPC); epcascii = epcascii.Replace("\0", ""); List real_Readdatas = databaseService._helper.Query(x => x.rfidascii == epcascii); //如果不存在则写入 if (real_Readdatas.Count <= 0) //if (true) { //验证是否已获取序列号 if (string.IsNullOrEmpty(deviceInfo.SerialNo)) { return; } deviceInfo.ReadTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); //拼接订单号写入标签 string WriteData = deviceInfo.OrderNo + deviceInfo.LineNo + DateTime.Now.ToString("yy") + deviceInfo.NextProductNo + deviceInfo.SerialNo; CurrentState = "写入中"; LastRFIDEPC = tagInfos[0].EPCstring; //写入前暂停心跳和连续盘点 StopInventoryTimer(iCombineId); await rfidInfo.Set_HeartBeat(0); Task.Delay(100).Wait(); //处理写入字符串,并写入 //var originBytes = tagInfos[0].EPC.Where(b => b != 0x00).ToArray(); bool writeflag = rfidInfo.Set_Write(tagInfos[0].EPC, WriteData).GetAwaiter().GetResult(); WriteTime++; if (writeflag) //写入成功 { LastWrite = WriteData; IsVerify = true; WriteTime = 0; //开始二次验证 rfidInfo.Set_BeginIdentify().GetAwaiter().GetResult(); // 启动验证超时检测 _verifyCts?.Cancel(); _verifyCts = new CancellationTokenSource(); var token = _verifyCts.Token; var capturedTagInfos = tagInfos; var timeoutMs = deviceConfig.VerifyTimeoutMilliseconds ?? 20000; _ = Task.Run(async () => { try { await Task.Delay(timeoutMs, token); Log.Error($"二次验证超时未读到标签,标签已离开,记为写入失败"); await DataAdd(iCombineId, capturedTagInfos, false); } catch (TaskCanceledException) { } }, token); //开启定时盘点和心跳 StartInventoryTimer(iCombineId, deviceConfig.InventoryIntervalSeconds.Value); await rfidInfo.Set_HeartBeat(5); return; } else //写入失败 { Log.Error($"第{WriteTime + 1}次写入失败,重试中..."); //重试前再读取一次标签 rfidInfo.Set_BeginIdentify().GetAwaiter().GetResult(); //设置下次读取超时 _writeCts?.Cancel(); _writeCts = new CancellationTokenSource(); var token = _writeCts.Token; var capturedTagInfos = tagInfos; var timeoutMs = deviceConfig.WriteTimeoutMilliseconds ?? 10000; _ = Task.Run(async () => { try { await Task.Delay(timeoutMs, token); Log.Error($"写入前读取超时,[{tagInfos[0].EPCstring}] 记为写入失败"); await DataAdd(iCombineId, capturedTagInfos, false); WriteTime = 0; } catch (TaskCanceledException) { } }, token); StartInventoryTimer(iCombineId, deviceConfig.InventoryIntervalSeconds.Value); await rfidInfo.Set_HeartBeat(5); Task.Delay(100).Wait(); } return; } else { await Task.Run(async () => { await Task.Delay(1000); await rfidInfo!.Set_BeginIdentify(); CurrentState = "盘点中"; }); } } else //二次验证流程 { var judgeString = Encoding.ASCII.GetString(tagInfos[0].EPC); judgeString = judgeString.Replace("\0", ""); //二次验证如果不通过 重新开始盘点 if (judgeString != LastWrite) { // 读到标签但数据不匹配,重置超时(标签仍在天线范围内) _verifyCts?.Cancel(); _verifyCts = new CancellationTokenSource(); var token = _verifyCts.Token; var capturedTagInfos = tagInfos; var timeoutMs = deviceConfig?.VerifyTimeoutMilliseconds ?? 20000; _ = Task.Run(async () => { try { await Task.Delay(timeoutMs, token); Log.Error($"二次验证超时写入标签超时,标签已离开,记为写入失败"); await DataAdd(iCombineId, capturedTagInfos, false); } catch (TaskCanceledException) { } }, token); IsVerify = false; var tempEPC = LastRFIDEPC; rfidInfo.Set_BeginIdentify().GetAwaiter().GetResult(); LastRFIDEPC = tempEPC; CurrentState = "盘点中"; return; } else //二次验证通过 { _verifyCts?.Cancel(); Log.Information($"验证成功"); //插入成功记录 await DataAdd(iCombineId, tagInfos, true); return; } } } catch (Exception e) { Log.Error($"读结果准备写入时异常:{e.Message}"); CurrentState = "空闲"; } } /// /// 插入记录 /// /// /// /// private async Task DataAdd(string iCombineId, List tagInfos, bool isSuccess) { var deviceInfo = Deviceinfo.FirstOrDefault(x => x.Deviceid == iCombineId); var rfidInfo = rfidList.FirstOrDefault(x => x.deviceid == iCombineId); var deviceConfig = appConfig.deviceInfoConfig.FirstOrDefault(x => x.Deviceid == iCombineId); IsVerify = false; deviceInfo.WriteTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); deviceInfo.WriteStatus = isSuccess ? "成功" : "失败"; LastWriteState = isSuccess ? "成功" : "失败"; deviceInfo.RfidASCII = LastWrite; deviceInfo.RfidEPC = LastRFIDEPC; deviceInfo.SerialNo = (Convert.ToInt32(deviceInfo.SerialNo) + 1).ToString("D2"); //保存写入记录 real_readdata real_Readdata = new real_readdata() { objid = Guid.NewGuid().ToString(), serialno = (Convert.ToInt32(deviceInfo.SerialNo) - 1).ToString("D2"), orderno = deviceInfo.OrderNo, lineno = deviceInfo.LineNo, producttype = deviceInfo.ProductType, rfidepc = deviceInfo.RfidEPC, rfidascii = LastWrite, readtime = Convert.ToDateTime(deviceInfo.ReadTime), writetime = Convert.ToDateTime(deviceInfo.WriteTime), writestatus = deviceInfo.WriteStatus }; //插入到数据库历史记录中 var a = databaseService._helper.Insert(real_Readdata); //插入记录到首页临时数据显示 AddRFIDData(iCombineId, tagInfos); LastRFIDEPC = ""; LastWrite = ""; await rfidInfo.Set_BeginIdentify(); await Task.Delay(100); StartInventoryTimer(iCombineId, deviceConfig.InventoryIntervalSeconds.Value); await rfidInfo.Set_HeartBeat(5); CurrentState = "盘点中"; return; } #endregion #region 数据流相关 /// /// 开始订单初次流程 /// /// /// private void RefreshOrderNo(object recipient, Real_DataInfo real_Data) { //查询当前订单产线最大序列号 List real_Readdatas = databaseService._helper.Query(x => x.orderno == real_Data.OrderNo && x.lineno == real_Data.LineNo); string SNo = ""; if (real_Readdatas.Count > 0) { SNo = real_Readdatas.Max(x => x.serialno); SNo = (Convert.ToInt32(SNo) + 1).ToString("D2"); } else { SNo = "1"; } Deviceinfo.FirstOrDefault(x => x.Deviceid == real_Data.Deviceid).SerialNo = Convert.ToInt32(SNo).ToString("D2"); Deviceinfo.FirstOrDefault(x => x.Deviceid == real_Data.Deviceid).OrderNo = real_Data.OrderNo; Deviceinfo.FirstOrDefault(x => x.Deviceid == real_Data.Deviceid).ProductType = real_Data.ProductType; Deviceinfo.FirstOrDefault(x => x.Deviceid == real_Data.Deviceid).LineNo = real_Data.LineNo; Deviceinfo.FirstOrDefault(x => x.Deviceid == real_Data.Deviceid).RfidCount = real_Data.RfidCount; Deviceinfo.FirstOrDefault(x => x.Deviceid == real_Data.Deviceid).NextProductNo = real_Data.NextProductNo; rfidList.FirstOrDefault(x => x.deviceid == real_Data.Deviceid).Set_BeginIdentify().GetAwaiter().GetResult(); IsVerify = false; CurrentState = "盘点中"; // 启动定时盘点 var deviceConfig = appConfig.deviceInfoConfig.FirstOrDefault(x => x.Deviceid == real_Data.Deviceid); if (deviceConfig?.InventoryIntervalSeconds > 0) { StartInventoryTimer(real_Data.Deviceid, deviceConfig.InventoryIntervalSeconds.Value); } } /// /// 停止盘点消息 /// private void StopMessage(object o, string e) { var rfid = rfidList.FirstOrDefault(x => x.deviceid == e); StopInventoryTimer(e); var res = rfid.Set_StopIdentify().GetAwaiter().GetResult(); if (res) { MessageBox.Show("停止盘点成功!", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } else { MessageBox.Show("停止盘点失败!", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } CurrentState = "空闲"; } /// /// 初次加载设备信息 /// private void LoadDeviceInfo() { List DeviceInfos = appConfig.deviceInfoConfig.Where(x => x.Collectid == appConfig.StationCode && x.Deleteflag == 0).ToList(); List real_DataInfos = new List(); foreach (var item in DeviceInfos) { Real_DataInfo real_DataInfo = new Real_DataInfo() { Name = item.Name, Deviceid = item.Deviceid, Connectstr = item.Connectstr, LineName = item.Name, LineNo = item.Addr, OrderNo = "", ProductType = "", WriteCount = "", RfidCount = "", IsOnline = "未连接", RfidASCII = "", RfidEPC = "", ReadTime = "", WriteTime = "", ProductStatus = "", WriteStatus = "", WriteDelaySet = item.WriteDelaySet }; real_DataInfos.Add(real_DataInfo); } App.Current.Dispatcher.Invoke(() => { Deviceinfo.Clear(); foreach (var item in real_DataInfos) { Real_DataInfo real_DataInfo = new Real_DataInfo() { Name = item.Name, Deviceid = item.Deviceid, Connectstr = item.Connectstr, LineName = item.Name, LineNo = item.LineNo, OrderNo = item.OrderNo, ProductType = item.ProductType, WriteCount = item.WriteCount, RfidCount = item.RfidCount, IsOnline = item.IsOnline, RfidASCII = item.RfidASCII, ReadTime = item.ReadTime, WriteTime = item.WriteTime, ProductStatus = item.ProductStatus, WriteStatus = item.WriteStatus, RfidEPC = item.RfidEPC, WriteDelaySet = item.WriteDelaySet }; Deviceinfo.Add(real_DataInfo); } }); } /// /// 添加数据的方法 /// /// /// public void AddRFIDData(string iCombineId, List tagInfos) { Task.Run(() => { App.Current.Dispatcher.Invoke(() => { RFIDHistoryRecords.Insert(0, new RFIDRecord { OrderNumber = Deviceinfo.FirstOrDefault(x => x.Deviceid == iCombineId).OrderNo, LineNumber = Deviceinfo.FirstOrDefault(x => x.Deviceid == iCombineId).LineNo, ProductType = Deviceinfo.FirstOrDefault(x => x.Deviceid == iCombineId).ProductType, OriginalEPC = Deviceinfo.FirstOrDefault(x => x.Deviceid == iCombineId).RfidEPC, RFIDCode = Deviceinfo.FirstOrDefault(x => x.Deviceid == iCombineId).RfidASCII, ReadTime = Deviceinfo.FirstOrDefault(x => x.Deviceid == iCombineId).ReadTime, WriteTime = Deviceinfo.FirstOrDefault(x => x.Deviceid == iCombineId).ReadTime, WriteStatus = Deviceinfo.FirstOrDefault(x => x.Deviceid == iCombineId).WriteStatus // 模拟1条失败数据 }); }); }); } #endregion #region 设备状态检测 private void StartCheckStatus() { Task.Run(async () => { while (true) { try { #region RFID状态 //RefreshLogMessage("检测设备状态"); var batches = SplitListIntoBatches(rfidList, 10); for (int i = 0; i < batches.Count; i++) { var currentBatch = batches[i]; // 显示当前批次信息(UI线程) Console.WriteLine($"{DateTime.Now}开始检测第{i + 1}批(共{currentBatch.Count}个设备)\r\n"); // 异步检测当前批次的设备状态(不阻塞UI) await DetectDeviceBatchAsync(currentBatch); // 批次之间的间隔(最后一批无需等待) if (i < batches.Count - 1) { Console.WriteLine($"{DateTime.Now}第{i + 1}批检测完成,共{batches.Count}批,等待{1000 / 1000}秒后检测下一批\r\n"); await Task.Delay(10); } } #endregion RFID状态 } catch (Exception ex) { Log.Information($"监听设备状态异常:{ex.Message}"); } await Task.Delay(1000 * 20); } }); } private List> SplitListIntoBatches(List sourceList, int batchSize) { var batches = new List>(); for (int i = 0; i < sourceList.Count; i += batchSize) { // 截取每批的设备(最后一批可能不足10个) var batch = sourceList.Skip(i).Take(batchSize).ToList(); batches.Add(batch); } return batches; } private async Task DetectDeviceBatchAsync(List batch) { // 并行检测当前批次的设备(可选,根据接口性能调整) var detectionTasks = batch.Select(device => DetectSingleDeviceAsync(device)); // 等待当前批次所有设备检测完成 await Task.WhenAll(detectionTasks); } /// /// 重连核心算法 /// /// /// private async Task DetectSingleDeviceAsync(RfidAbsractFactory device) { try { //基于心跳检测的断线重连机制 if (GloalVar.HeartBeatRecoard.TryGetValue(device.deviceid, out var value)) { if (value.AddSeconds(15) < DateTime.Now) { await Reconnect(device); Deviceinfo.FirstOrDefault(x => x.Deviceid == device.deviceid).IsOnline = "已连接"; } } else //第一次的逻辑 { await Reconnect(device); Deviceinfo.FirstOrDefault(x => x.Deviceid == device.deviceid).IsOnline = "已连接"; var res = false; //无限获取心跳返回报文 Log.Information($"准备第一次获取心跳"); res = await device.Set_HeartBeat(5); } } catch (Exception ex) { Log.Information($"更新RFID状态异常:{ex.Message}", ex); } } /// /// 无限重连 /// /// /// private async Task Reconnect(RfidAbsractFactory device) { var res = false; do { await Task.Delay(1000); Deviceinfo.FirstOrDefault(x => x.Deviceid == device.deviceid).IsOnline = "未连接"; Log.Information($"[{device.deviceid}]:[{device.ip}:{device.port}]连接中..."); res = await device.ConnectAsync(device.ip, device.port, device.deviceid); } while (!res); } #endregion #region 定时盘点 /// /// 启动定时盘点 /// private void StartInventoryTimer(string deviceId, int intervalSeconds) { StopInventoryTimer(deviceId); var timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(intervalSeconds) }; timer.Tick += (s, e) => OnInventoryTimerTick(deviceId); timer.Start(); //OnInventoryTimerTick(deviceId); _inventoryTimers[deviceId] = timer; Log.Information($"设备 {deviceId} 启动定时盘点,间隔 {intervalSeconds} ms"); } /// /// 停止定时盘点 /// private void StopInventoryTimer(string deviceId) { if (_inventoryTimers.TryGetValue(deviceId, out var timer)) { timer.Stop(); _inventoryTimers.Remove(deviceId); Log.Information($"设备 {deviceId} 停止定时盘点"); } } /// /// 定时盘点回调 /// private async void OnInventoryTimerTick(string deviceId) { try { var rfid = rfidList.FirstOrDefault(x => x.deviceid == deviceId); if (rfid != null) { //Log.Information($"设备 {deviceId} 执行定时盘点"); //await rfid.Set_StopIdentify(); //await Task.Delay(100); rfid.Set_BeginIdentify().GetAwaiter().GetResult(); } } catch (Exception ex) { Log.Error($"设备 {deviceId} 定时盘点异常: {ex.Message}"); } } #endregion } }