You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

916 lines
36 KiB
C#

using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using GalaSoft.MvvmLight;
3 months ago
using Microsoft.Extensions.DependencyInjection;
using NVelocity.Runtime.Directive;
3 months ago
using Serilog;
using SlnMesnac.Common;
3 months ago
using SlnMesnac.Config;
using SlnMesnac.Model.domain;
using SlnMesnac.Model.dto;
using SlnMesnac.Model.Enum;
using SlnMesnac.Repository;
3 months ago
using SlnMesnac.Repository.service;
using SlnMesnac.Repository.service.Impl;
3 months ago
using SlnMesnac.Rfid;
using SlnMesnac.Rfid.Enum;
3 months ago
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;
3 months ago
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Markup;
3 months ago
using System.Windows.Threading;
using System.Xml.Serialization;
using TouchSocket.Core;
3 months ago
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 = "";
3 months ago
private SerilogHelper _logger;
//private ISqlSugarClient? sqlSugarClient;
3 months ago
//容器里面的读写器集合
public List<RfidAbsractFactory> rfidList;
private AppConfig appConfig;
private MeshttpClient meshttpClient;
public TcpServer _TcpServer;
private DispatcherTimer _timer;
private Dictionary<string, DispatcherTimer> _inventoryTimers = new Dictionary<string, DispatcherTimer>();
private HashSet<string> _tickingDevices = new HashSet<string>();
private HashSet<string> _writingDevices = new HashSet<string>();
3 months ago
private ObservableCollection<RFIDRecord> _rfidHistoryRecords = new ObservableCollection<RFIDRecord>();
private RealReadDataImpl databaseService = RealReadDataImpl.Instance;
private System.Threading.Timer ReReadTimer;
/// <summary>
/// 每个设备的写入状态(支持多线并行)
/// </summary>
private class DeviceWriteState
{
public bool IsVerify;
public int WriteTime;
public string LastWrite = "";
public string Real_LastRFIDEPC = "";
public CancellationTokenSource? VerifyCts;
public CancellationTokenSource? WriteCts;
}
private Dictionary<string, DeviceWriteState> _deviceStates = new();
private DeviceWriteState GetDeviceState(string deviceId)
{
if (!_deviceStates.TryGetValue(deviceId, out var state))
{
state = new DeviceWriteState();
_deviceStates[deviceId] = state;
}
return state;
}
#endregion
#region 关联属性
3 months ago
public ObservableCollection<RFIDRecord> RFIDHistoryRecords
{
get { return _rfidHistoryRecords; }
set
{
_rfidHistoryRecords = value;
RaisePropertyChanged(() => RFIDHistoryRecords);
}
}
ChangeTypeViewModel ChangeTypeView;
private ObservableCollection<Real_DataInfo> _Deviceinfo = new ObservableCollection<Real_DataInfo>();
public ObservableCollection<Real_DataInfo> Deviceinfo
{
get { return _Deviceinfo; }
set
{
_Deviceinfo = value;
RaisePropertyChanged(() => Deviceinfo);
}
}
3 months ago
/// <summary>
/// 日期时间
/// </summary>
private DateTime _currentDateTime;
public DateTime CurrentDateTime
{
get => _currentDateTime;
set
{
if (_currentDateTime != value)
{
_currentDateTime = value;
RaisePropertyChanged(() => CurrentDateTime);
}
}
}
/// <summary>
/// 上一次写入状态
/// </summary>
private string _lastWriteState;
public string LastWriteState
{
get => _lastWriteState;
set
{
if (_lastWriteState != value)
{
_lastWriteState = value;
RaisePropertyChanged(() => LastWriteState);
}
}
}
/// <summary>
/// 当前状态 空闲 盘点中 写入中
/// </summary>
private string _CurrentState = "空闲";
public string CurrentState
{
get => _CurrentState;
set
{
if (_CurrentState != value)
{
_CurrentState = value;
RaisePropertyChanged(() => CurrentState);
}
}
}
#endregion
#region 构造函数
3 months ago
public ProductionLineViewModel()
{
ChangeTypeView = App.ServiceProvider.GetService<ChangeTypeViewModel>();
// 构造函数里注册
WeakReferenceMessenger.Default.Register<Real_DataInfo>(this, RefreshOrderNo);
WeakReferenceMessenger.Default.Register<string, string>(this, "Cancel", StopMessage);
_StringChange = App.ServiceProvider.GetService<StringChange>();
3 months ago
_logger = App.ServiceProvider.GetService<SerilogHelper>();
appConfig = App.ServiceProvider.GetService<AppConfig>();
//sqlSugarClient = App.ServiceProvider.GetService<ISqlSugarClient>();
3 months ago
_TcpServer = App.ServiceProvider.GetRequiredService<TcpServer>();
rfidList = App.ServiceProvider.GetRequiredService<List<RfidAbsractFactory>>();
rfidList.ForEach(rfid =>
{
3 months ago
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();
3 months ago
Log.Information("RFID输送带系统启动");
3 months ago
}
#endregion
#region 核心写入算法
3 months ago
/// <summary>
/// 接收到连续盘点标签返回
/// </summary>
/// <param name="iCombineId"></param>
/// <param name="tagInfos"></param>
private async void RecvIdentifyData_Instance(string iCombineId, List<TagInfo> tagInfos)
{
// 防重入:同一设备正在写入中,跳过本次标签读取
if (!_writingDevices.Add(iCombineId))
return;
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);
3 months ago
try
{
var state = GetDeviceState(iCombineId);
state.WriteCts?.Cancel();
//初次写入
if (!state.IsVerify)
3 months ago
{
//写入前等待标签稳定
if (!state.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_readdata> 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");
//拼接订单号写入标签OrderNo + 处理后的ProductOrder + 序号
string processedProductOrder = ProcessProductOrder(deviceInfo.ProductOrder);
string WriteData = deviceInfo.OrderNo + processedProductOrder + deviceInfo.SerialNo;
deviceInfo.CurrentState = "写入中";
//上次读的EPC
//LastRFIDEPC = tagInfos[0].EPCstring;
//保存最原始的EPC仅第一次读取时保存后续重试不覆盖
if (string.IsNullOrEmpty(state.Real_LastRFIDEPC))
{
state.Real_LastRFIDEPC = tagInfos[0].EPCstring;
}
//写入前暂停心跳和连续盘点
StopInventoryTimer(iCombineId);
await rfidInfo.Set_HeartBeat(0);
await Task.Delay(100);
//暂停订单自动刷新,防止写入过程中订单切换
WeakReferenceMessenger.Default.Send(string.Empty, "PauseOrderRefresh");
/////////////////////////////////处理写入字符串,并写入////////////////////////////////////////
//var originBytes = tagInfos[0].EPC.Where(b => b != 0x00).ToArray();
bool writeflag = await rfidInfo.Set_Write(tagInfos[0].EPC, WriteData);
/////////////////////////////////处理写入字符串,并写入////////////////////////////////////////
state.WriteTime++;
if (writeflag) //写入成功
{
state.LastWrite = WriteData;
state.IsVerify = true;
state.WriteTime = 0;
//开启定时盘点和心跳
StartInventoryTimer(iCombineId, deviceConfig.InventoryIntervalSeconds.Value);
await rfidInfo.Set_HeartBeat(5);
//开始二次验证
await rfidInfo.Set_BeginIdentify();
// 启动验证超时检测
state.VerifyCts?.Cancel();
state.VerifyCts = new CancellationTokenSource();
var token = state.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);
return;
}
else //写入失败
{
Log.Error($"第{state.WriteTime + 1}次写入失败,重试中...");
//开启定时盘点和心跳
StartInventoryTimer(iCombineId, deviceConfig.InventoryIntervalSeconds.Value);
await rfidInfo.Set_HeartBeat(5);
await rfidInfo.Set_BeginIdentify();
//设置下次读取超时
state.WriteCts?.Cancel();
state.WriteCts = new CancellationTokenSource();
var token = state.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);
state.WriteTime = 0;
}
catch (TaskCanceledException) { }
}, token);
await Task.Delay(100);
}
return;
}
else
{
await Task.Run(async () =>
{
await Task.Delay(1000);
//StartInventoryTimer(iCombineId, deviceConfig.InventoryIntervalSeconds.Value);
await rfidInfo!.Set_BeginIdentify();
deviceInfo.CurrentState = "盘点中";
});
}
3 months ago
}
else //二次验证流程
{
var judgeString = Encoding.ASCII.GetString(tagInfos[0].EPC);
judgeString = judgeString.Replace("\0", "");
//二次验证如果不通过 重新开始盘点
if (judgeString != state.LastWrite)
{
// 读到标签但数据不匹配,重置超时(标签仍在天线范围内)
state.VerifyCts?.Cancel();
state.VerifyCts = new CancellationTokenSource();
var token = state.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);
state.IsVerify = false;
//state.Real_LastRFIDEPC = LastRFIDEPC;
rfidInfo.Set_BeginIdentify().GetAwaiter().GetResult();
deviceInfo.CurrentState = "盘点中";
return;
}
else //二次验证通过
{
state.VerifyCts?.Cancel();
Log.Information($"验证成功");
//插入成功记录
await DataAdd(iCombineId, tagInfos, true);
return;
}
}
3 months ago
}
catch (Exception e)
{
Log.Error($"读结果准备写入时异常:{e.Message}");
if (deviceInfo != null)
deviceInfo.CurrentState = "空闲";
//开启定时盘点和心跳
rfidInfo.Set_BeginIdentify().GetAwaiter().GetResult();
StartInventoryTimer(iCombineId, deviceConfig.InventoryIntervalSeconds.Value);
await rfidInfo.Set_HeartBeat(5);
3 months ago
}
finally
{
_writingDevices.Remove(iCombineId);
}
3 months ago
}
/// <summary>
/// 插入记录
/// </summary>
/// <param name="iCombineId"></param>
/// <param name="tagInfos"></param>
/// <param name="isSuccess"></param>
private async Task DataAdd(string iCombineId, List<TagInfo> tagInfos, bool isSuccess)
{
var deviceInfo = Deviceinfo.FirstOrDefault(x => x.Deviceid == iCombineId);
var rfidInfo = rfidList.FirstOrDefault(x => x.deviceid == iCombineId);
var state = GetDeviceState(iCombineId);
var deviceConfig = appConfig.deviceInfoConfig.FirstOrDefault(x => x.Deviceid == iCombineId);
state.IsVerify = false;
deviceInfo.WriteTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
deviceInfo.WriteStatus = isSuccess ? "成功" : "失败";
deviceInfo.LastWriteState = isSuccess ? "成功" : "失败";
deviceInfo.RfidASCII = state.LastWrite;
deviceInfo.RfidEPC = state.Real_LastRFIDEPC;
deviceInfo.SerialNo = (Convert.ToInt32(deviceInfo.SerialNo) + 1).ToString("D2");
//更新下一个要写入的EPC预览
deviceInfo.NextWriteEPC = deviceInfo.OrderNo + ProcessProductOrder(deviceInfo.ProductOrder) + deviceInfo.SerialNo;
//保存写入记录
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,
productorder = ProcessProductOrder(deviceInfo.ProductOrder),
rfidepc = deviceInfo.RfidEPC,
rfidascii = state.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 = "";
state.Real_LastRFIDEPC = "";
state.LastWrite = "";
//写入完成,恢复订单自动刷新
WeakReferenceMessenger.Default.Send(string.Empty, "ResumeOrderRefresh");
await rfidInfo.Set_BeginIdentify();
await Task.Delay(100);
//StartInventoryTimer(iCombineId, deviceConfig.InventoryIntervalSeconds.Value);
//await rfidInfo.Set_HeartBeat(5);
deviceInfo.CurrentState = "盘点中";
return;
}
/// <summary>
/// 处理ProductOrder去掉前导字母和中间的"-"
/// 例:"GS426-0250" → "4260250""GSW426-0250" → "4260250"
/// </summary>
private static string ProcessProductOrder(string productOrder)
{
if (string.IsNullOrEmpty(productOrder))
return "";
return System.Text.RegularExpressions.Regex.Replace(productOrder, @"^[A-Za-z]+|-", "");
}
#endregion
#region 数据流相关
/// <summary>
/// 开始订单初次流程
/// </summary>
/// <param name="recipient"></param>
/// <param name="real_Data"></param>
private void RefreshOrderNo(object recipient, Real_DataInfo real_Data)
{
var deviceInfo = Deviceinfo.FirstOrDefault(x => x.Deviceid == real_Data.Deviceid);
var deviceConfig = appConfig.deviceInfoConfig.FirstOrDefault(x => x.Deviceid == real_Data.Deviceid);
//检测OrderNo或ProductOrder是否发生变化变化则重置计数器
bool orderChanged = deviceInfo.OrderNo != real_Data.OrderNo
|| deviceInfo.ProductOrder != real_Data.ProductOrder;
if (orderChanged)
{
//查询当前订单+产品订单下的最大序列号
string processedPo = ProcessProductOrder(real_Data.ProductOrder);
List<real_readdata> real_Readdatas = databaseService._helper.Query(x =>
x.orderno == real_Data.OrderNo && x.productorder == processedPo);
string SNo = "";
if (real_Readdatas.Count > 0)
{
SNo = real_Readdatas.Max(x => x.serialno);
SNo = (Convert.ToInt32(SNo) + 1).ToString("D2");
}
else
{
SNo = "01";
}
deviceInfo.SerialNo = SNo;
}
deviceInfo.OrderNo = real_Data.OrderNo;
deviceInfo.ProductType = real_Data.ProductType;
deviceInfo.LineNo = real_Data.LineNo;
deviceInfo.RfidCount = real_Data.RfidCount;
deviceInfo.NextProductNo = real_Data.NextProductNo;
deviceInfo.ProductOrder = real_Data.ProductOrder;
//更新下一个要写入的EPC预览
deviceInfo.NextWriteEPC = deviceInfo.OrderNo + ProcessProductOrder(deviceInfo.ProductOrder) + deviceInfo.SerialNo;
rfidList.FirstOrDefault(x => x.deviceid == real_Data.Deviceid).Set_BeginIdentify().GetAwaiter().GetResult();
var state = GetDeviceState(real_Data.Deviceid);
state.IsVerify = false;
state.Real_LastRFIDEPC = "";
deviceInfo.CurrentState = "盘点中";
// 启动定时盘点
if (deviceConfig?.InventoryIntervalSeconds > 0)
3 months ago
{
StartInventoryTimer(real_Data.Deviceid, deviceConfig.InventoryIntervalSeconds.Value);
3 months ago
}
}
/// <summary>
/// 停止盘点消息
/// </summary>
private void StopMessage(object o, string e)
3 months ago
{
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);
}
var deviceInfo = Deviceinfo.FirstOrDefault(x => x.Deviceid == e);
if (deviceInfo != null)
deviceInfo.CurrentState = "空闲";
}
/// <summary>
/// 初次加载设备信息
/// </summary>
private void LoadDeviceInfo()
{
List<DeviceInfoConfig> DeviceInfos = appConfig.deviceInfoConfig.Where(x => x.Collectid == appConfig.StationCode && x.Deleteflag == 0).ToList();
List<Real_DataInfo> real_DataInfos = new List<Real_DataInfo>();
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);
}
3 months ago
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);
}
});
}
/// <summary>
/// 添加数据的方法
/// </summary>
/// <param name="iCombineId"></param>
/// <param name="tagInfos"></param>
public void AddRFIDData(string iCombineId, List<TagInfo> tagInfos)
{
Task.Run(() =>
3 months ago
{
App.Current.Dispatcher.Invoke(() =>
3 months ago
{
var deviceInfo = Deviceinfo.FirstOrDefault(x => x.Deviceid == iCombineId);
if (deviceInfo == null) return;
RFIDHistoryRecords.Insert(0, new RFIDRecord
{
OrderNumber = deviceInfo.OrderNo,
LineNumber = deviceInfo.LineNo,
ProductType = deviceInfo.ProductType,
OriginalEPC = deviceInfo.RfidEPC,
RFIDCode = deviceInfo.RfidASCII,
ReadTime = deviceInfo.ReadTime,
WriteTime = deviceInfo.ReadTime,
WriteStatus = deviceInfo.WriteStatus,
DeviceId = iCombineId
});
//更新过滤后的历史记录
RefreshFilteredRecords();
3 months ago
});
});
}
/// <summary>
/// 当前选中的设备IDTab切换时更新
/// </summary>
private string? _selectedDeviceId;
public string? SelectedDeviceId
{
get => _selectedDeviceId;
set
{
if (_selectedDeviceId != value)
{
_selectedDeviceId = value;
RaisePropertyChanged(() => SelectedDeviceId);
RefreshFilteredRecords();
}
}
}
private ObservableCollection<RFIDRecord> _filteredRFIDHistoryRecords = new();
/// <summary>
/// 按选中设备过滤后的RFID历史记录
/// </summary>
public ObservableCollection<RFIDRecord> FilteredRFIDHistoryRecords
{
get => _filteredRFIDHistoryRecords;
set
{
_filteredRFIDHistoryRecords = value;
RaisePropertyChanged(() => FilteredRFIDHistoryRecords);
}
}
private void RefreshFilteredRecords()
{
var filtered = string.IsNullOrEmpty(_selectedDeviceId)
? RFIDHistoryRecords.ToList()
: RFIDHistoryRecords.Where(x => x.DeviceId == _selectedDeviceId).ToList();
FilteredRFIDHistoryRecords.Clear();
foreach (var item in filtered)
{
FilteredRFIDHistoryRecords.Add(item);
}
}
#endregion
#region 设备状态检测
3 months ago
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)
{
3 months ago
Log.Information($"监听设备状态异常:{ex.Message}");
3 months ago
}
await Task.Delay(1000 * 20);
3 months ago
}
});
}
private List<List<RfidAbsractFactory>> SplitListIntoBatches(List<RfidAbsractFactory> sourceList, int batchSize)
{
var batches = new List<List<RfidAbsractFactory>>();
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<RfidAbsractFactory> batch)
{
// 并行检测当前批次的设备(可选,根据接口性能调整)
var detectionTasks = batch.Select(device => DetectSingleDeviceAsync(device));
// 等待当前批次所有设备检测完成
await Task.WhenAll(detectionTasks);
}
/// <summary>
/// 重连核心算法
/// </summary>
/// <param name="device"></param>
/// <returns></returns>
3 months ago
private async Task DetectSingleDeviceAsync(RfidAbsractFactory device)
{
try
{
//基于心跳检测的断线重连机制
if (GloalVar.HeartBeatRecoard.TryGetValue(device.deviceid, out var value))
3 months ago
{
if (value.AddSeconds(15) < DateTime.Now)
3 months ago
{
await Reconnect(device);
3 months ago
Deviceinfo.FirstOrDefault(x => x.Deviceid == device.deviceid).IsOnline = "已连接";
}
}
else //第一次的逻辑
3 months ago
{
await Reconnect(device);
Deviceinfo.FirstOrDefault(x => x.Deviceid == device.deviceid).IsOnline = "已连接";
var res = false;
//无限获取心跳返回报文
Log.Information($"准备第一次获取心跳");
res = await device.Set_HeartBeat(5);
3 months ago
}
}
catch (Exception ex)
{
3 months ago
Log.Information($"更新RFID状态异常:{ex.Message}", ex);
3 months ago
}
}
/// <summary>
/// 无限重连
/// </summary>
/// <param name="device"></param>
/// <returns></returns>
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 定时盘点
/// <summary>
/// 启动定时盘点(旧版 - 存在线程问题,已废弃)
/// </summary>
//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");
//}
/// <summary>
/// 启动定时盘点(修复版)
/// 修复内容:
/// 1. DispatcherTimer 强制关联 UI 线程 Dispatcher避免在后台线程创建导致 Tick 不触发
/// 2. 参数更名为 intervalMilliseconds修正参数名与实际单位的误导
/// 3. StopInventoryTimer 也同步到 UI 线程执行,保证字典操作线程安全
/// </summary>
private void StartInventoryTimer(string deviceId, int intervalMilliseconds)
{
var uiDispatcher = System.Windows.Application.Current.Dispatcher;
uiDispatcher.Invoke(() =>
{
StopInventoryTimer(deviceId);
var timer = new DispatcherTimer(DispatcherPriority.Normal, uiDispatcher)
{
Interval = TimeSpan.FromMilliseconds(intervalMilliseconds)
};
timer.Tick += (s, e) => OnInventoryTimerTick(deviceId);
timer.Start();
_inventoryTimers[deviceId] = timer;
Log.Information($"设备 {deviceId} 启动定时盘点,间隔 {intervalMilliseconds} ms");
});
}
/// <summary>
/// 停止定时盘点
/// </summary>
private void StopInventoryTimer(string deviceId)
{
if (_inventoryTimers.TryGetValue(deviceId, out var timer))
{
timer.Stop();
_inventoryTimers.Remove(deviceId);
Log.Information($"设备 {deviceId} 停止定时盘点");
}
}
/// <summary>
/// 定时盘点回调(加防重入保护)
/// </summary>
private async void OnInventoryTimerTick(string deviceId)
{
// 防重入:上一次 Set_BeginIdentify 未完成时跳过本次 Tick
if (!_tickingDevices.Add(deviceId))
return;
try
{
var rfid = rfidList.FirstOrDefault(x => x.deviceid == deviceId);
if (rfid != null)
{
Log.Information($"设备 {deviceId} 执行定时盘点");
//await rfid.Set_StopIdentify();
//await Task.Delay(100);
await rfid.Set_BeginIdentify();
}
}
catch (Exception ex)
{
Log.Error($"设备 {deviceId} 定时盘点异常: {ex.Message}");
}
finally
{
_tickingDevices.Remove(deviceId);
}
}
#endregion
3 months ago
}
}