CAN驱动的重构V1
CAN报文的展示和处理
This commit is contained in:
@@ -231,7 +231,8 @@ namespace CapMachine.Wpf.Services
|
||||
{
|
||||
ToomossCanDrive.IsCycleSend = true;
|
||||
ToomossCanDrive.CmdData = CmdData;
|
||||
ToomossCanDrive.StartCycleSendMsg();
|
||||
//ToomossCanDrive.StartCycleSendMsg();
|
||||
ToomossCanDrive.StartPrecisionCycleSendMsg();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace CapMachine.Wpf.Services
|
||||
/// </summary>
|
||||
public class HighSpeedDataService : BindableBase
|
||||
{
|
||||
public HighSpeedDataService(ConfigService configService, ILogService logService, IFreeSql FreeSql,IContainerProvider containerProvider)
|
||||
public HighSpeedDataService(ConfigService configService, ILogService logService, IFreeSql FreeSql, IContainerProvider containerProvider)
|
||||
{
|
||||
ConfigService = configService;
|
||||
LogService = logService;
|
||||
@@ -112,13 +112,13 @@ namespace CapMachine.Wpf.Services
|
||||
// new CommMsg() { Category = "CAN5",MsgInfo = "0x000003E3",Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"),MsgData = "33 00 00 00 37 00 04 00"},
|
||||
//};
|
||||
|
||||
/// <summary>
|
||||
/// 周期定时器
|
||||
/// </summary>
|
||||
private System.Timers.Timer CycleTimer { get; set; }
|
||||
/// <summary>
|
||||
/// 周期定时器
|
||||
/// </summary>
|
||||
private System.Timers.Timer CycleTimer { get; set; }
|
||||
|
||||
|
||||
private bool _IsEnable=true;
|
||||
private bool _IsEnable = true;
|
||||
/// <summary>
|
||||
/// 是否启用
|
||||
/// </summary>
|
||||
@@ -208,7 +208,7 @@ namespace CapMachine.Wpf.Services
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region CSV Helper 数据保存CSV
|
||||
|
||||
|
||||
424
CapMachine.Wpf/Services/HightDriveMsgService.cs
Normal file
424
CapMachine.Wpf/Services/HightDriveMsgService.cs
Normal file
@@ -0,0 +1,424 @@
|
||||
using CapMachine.Wpf.CanDrive;
|
||||
using CapMachine.Wpf.Models.HighSpeed;
|
||||
using Prism.Ioc;
|
||||
using Prism.Mvvm;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Channels;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace CapMachine.Wpf.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// 高速驱动消息服务
|
||||
/// 负载高速的驱动数据的消息和转发
|
||||
/// </summary>
|
||||
public class HightDriveMsgService : BindableBase
|
||||
{
|
||||
|
||||
#region 字段和属性
|
||||
|
||||
private readonly ILogService LogService;
|
||||
|
||||
/// <summary>
|
||||
/// 接收数据Channel
|
||||
/// </summary>
|
||||
private readonly Channel<CommMsg> ReceiveChannel;
|
||||
|
||||
/// <summary>
|
||||
/// 转发数据Channel
|
||||
/// </summary>
|
||||
private readonly Channel<CommMsg> ForwardChannel;
|
||||
|
||||
/// <summary>
|
||||
/// 取消令牌
|
||||
/// </summary>
|
||||
private CancellationTokenSource TaskCancellationTokenSource;
|
||||
|
||||
/// <summary>
|
||||
/// 数据接受处理任务
|
||||
/// </summary>
|
||||
private Task ProcessTask;
|
||||
/// <summary>
|
||||
/// 数据转发处理任务
|
||||
/// </summary>
|
||||
private Task ForwardTask;
|
||||
|
||||
/// <summary>
|
||||
/// 显示的消息集合
|
||||
/// </summary>
|
||||
public ObservableCollection<CommMsg> DisplayMessages { get; set; } = new ObservableCollection<CommMsg>();
|
||||
|
||||
/// <summary>
|
||||
/// 最大显示消息数量
|
||||
/// </summary>
|
||||
public int MaxDisplayCount { get; set; } = 200;
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用CAN报文显示
|
||||
/// </summary>
|
||||
private bool _IsDisplayEnabled=true;
|
||||
public bool IsDisplayEnabled
|
||||
{
|
||||
get { return _IsDisplayEnabled; }
|
||||
set
|
||||
{
|
||||
SetProperty(ref _IsDisplayEnabled, value);
|
||||
if (!value)
|
||||
{
|
||||
// 不显示时清空数据节省内存
|
||||
App.Current.Dispatcher.Invoke(() => DisplayMessages.Clear());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用CAN数据转发
|
||||
/// </summary>
|
||||
private bool _IsForwardEnabled;
|
||||
public bool IsForwardEnabled
|
||||
{
|
||||
get { return _IsForwardEnabled; }
|
||||
set { SetProperty(ref _IsForwardEnabled, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 构造和初始化
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="containerProvider">容器服务提供者</param>
|
||||
/// <param name="logService">日志服务</param>
|
||||
public HightDriveMsgService(ILogService logService)
|
||||
{
|
||||
LogService = logService;
|
||||
|
||||
// 创建接收Channel,设置容量和溢出策略
|
||||
ReceiveChannel = Channel.CreateBounded<CommMsg>(new BoundedChannelOptions(100000)
|
||||
{
|
||||
FullMode = BoundedChannelFullMode.DropOldest, // 满时删除旧数据
|
||||
SingleReader = true, // 单一读取者
|
||||
SingleWriter = false // 允许多个写入者
|
||||
});
|
||||
|
||||
// 创建转发Channel
|
||||
ForwardChannel = Channel.CreateBounded<CommMsg>(new BoundedChannelOptions(100000)
|
||||
{
|
||||
FullMode = BoundedChannelFullMode.DropOldest,
|
||||
SingleReader = true,
|
||||
SingleWriter = false
|
||||
});
|
||||
|
||||
// 初始化服务
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化服务
|
||||
/// </summary>
|
||||
private void Initialize()
|
||||
{
|
||||
TaskCancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
// 启动数据处理任务
|
||||
ProcessTask = Task.Run(ProcessMessagesAsync);
|
||||
|
||||
// 启动数据转发任务
|
||||
ForwardTask = Task.Run(ForwardMessagesAsync);
|
||||
|
||||
//LogService.Info("HightDriveMsgService初始化完成");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 公共方法
|
||||
|
||||
/// <summary>
|
||||
/// 添加CAN消息进行处理
|
||||
/// </summary>
|
||||
/// <param name="message">CAN消息</param>
|
||||
/// <returns>是否添加成功</returns>
|
||||
public async Task<bool> AddMessageAsync(CommMsg message)
|
||||
{
|
||||
if (message == null) return false;
|
||||
|
||||
try
|
||||
{
|
||||
if (IsDisplayEnabled)
|
||||
{
|
||||
// 添加到接收Channel
|
||||
await ReceiveChannel.Writer.WriteAsync(message, TaskCancellationTokenSource.Token);
|
||||
}
|
||||
|
||||
|
||||
// 如果启用转发,也添加到转发Channel 需要判断目标的CAN是否已经打开,如果打开的话,则转发数据
|
||||
if (IsForwardEnabled)
|
||||
{
|
||||
await ForwardChannel.Writer.WriteAsync(message, TaskCancellationTokenSource.Token);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogService.Error($"添加CAN消息失败: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量添加CAN消息
|
||||
/// </summary>
|
||||
/// <param name="messages">消息集合</param>
|
||||
/// <returns>成功添加的消息数量</returns>
|
||||
public async Task<int> AddMessagesAsync(IEnumerable<CommMsg> messages)
|
||||
{
|
||||
if (messages == null) return 0;
|
||||
|
||||
int successCount = 0;
|
||||
foreach (var message in messages)
|
||||
{
|
||||
if (await AddMessageAsync(message))
|
||||
{
|
||||
successCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return successCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置转发目标CAN设备
|
||||
/// </summary>
|
||||
/// <param name="targetDevice">目标设备</param>
|
||||
public void SetForwardTarget(ToomossCan targetDevice)
|
||||
{
|
||||
//_targetCanDevice = targetDevice;
|
||||
LogService.Info($"设置转发目标设备: {(targetDevice != null ? "成功" : "未设置")}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清空显示消息
|
||||
/// </summary>
|
||||
public void ClearDisplayMessages()
|
||||
{
|
||||
App.Current.Dispatcher.Invoke(() => DisplayMessages.Clear());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region 私有方法
|
||||
|
||||
/// <summary>
|
||||
/// 批量处理消息提高效率
|
||||
/// </summary>
|
||||
private List<CommMsg> MessageBatch { get; set; } = new List<CommMsg>();
|
||||
|
||||
/// <summary>
|
||||
/// 接受的批次数量
|
||||
/// </summary>
|
||||
private int ReciveBatchCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 转发的批次数量
|
||||
/// </summary>
|
||||
private int ForwardBatchCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 异步处理接收到的消息
|
||||
/// </summary>
|
||||
private async Task ProcessMessagesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (await ReceiveChannel.Reader.WaitToReadAsync(TaskCancellationTokenSource.Token))
|
||||
{
|
||||
// 清空列表但保留容量
|
||||
MessageBatch.Clear();
|
||||
|
||||
// 读取最多100条消息或直到没有更多消息
|
||||
ReciveBatchCount = 0;
|
||||
while (ReciveBatchCount < 30 && ReceiveChannel.Reader.TryRead(out CommMsg message))
|
||||
{
|
||||
MessageBatch.Add(message);
|
||||
ReciveBatchCount++;
|
||||
}
|
||||
|
||||
if (MessageBatch.Count > 0 && IsDisplayEnabled)
|
||||
{
|
||||
// 在UI线程更新显示
|
||||
await App.Current.Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
foreach (var msg in MessageBatch)
|
||||
{
|
||||
DisplayMessages.Add(msg);
|
||||
|
||||
// 控制显示消息数量
|
||||
while (DisplayMessages.Count > MaxDisplayCount)
|
||||
{
|
||||
DisplayMessages.RemoveAt(0);
|
||||
}
|
||||
}
|
||||
}, DispatcherPriority.Background);
|
||||
}
|
||||
|
||||
// 避免CPU过度使用
|
||||
if (ReciveBatchCount == 0)
|
||||
{
|
||||
await Task.Delay(20);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException ex)
|
||||
{
|
||||
// 服务被取消,正常退出
|
||||
LogService.Error($" 服务被取消,正常退出: {ex.Message}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogService.Error($"消息处理任务异常: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步转发消息
|
||||
/// </summary>
|
||||
private async Task ForwardMessagesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (await ForwardChannel.Reader.WaitToReadAsync(TaskCancellationTokenSource.Token))
|
||||
{
|
||||
//// 只有在启用转发且目标设备可用时才处理 && _targetCanDevice != null && _targetCanDevice.OpenState
|
||||
//if (IsForwardEnabled)
|
||||
//{
|
||||
// // 批量收集转发消息
|
||||
// List<USB2CAN.CAN_MSG> canMessages = new List<USB2CAN.CAN_MSG>();
|
||||
// ForwardBatchCount = 0;
|
||||
|
||||
// // 一次最多处理50条消息
|
||||
// while (ForwardBatchCount < 50 && ForwardChannel.Reader.TryRead(out CommMsg message))
|
||||
// {
|
||||
// if (message.Category == "CAN" && !string.IsNullOrEmpty(message.MsgInfo))
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// // 转换为CAN_MSG格式
|
||||
// USB2CAN.CAN_MSG canMsg = new USB2CAN.CAN_MSG();
|
||||
// canMsg.Data = new byte[64];
|
||||
|
||||
// // 解析CAN ID
|
||||
// string msgIdHex = message.MsgInfo.Replace("0x", "");
|
||||
// canMsg.ID = Convert.ToUInt32(msgIdHex, 16);
|
||||
|
||||
// // 解析数据
|
||||
// string[] dataBytes = message.MsgData.Split('-');
|
||||
// canMsg.DataLen = (byte)dataBytes.Length;
|
||||
|
||||
// for (int i = 0; i < dataBytes.Length && i < 64; i++)
|
||||
// {
|
||||
// canMsg.Data[i] = Convert.ToByte(dataBytes[i], 16);
|
||||
// }
|
||||
|
||||
// canMessages.Add(canMsg);
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// LogService.Error($"转换CAN消息格式失败: {ex.Message}");
|
||||
// }
|
||||
// }
|
||||
|
||||
// ForwardBatchCount++;
|
||||
// }
|
||||
|
||||
// // 批量发送转发消息
|
||||
// if (canMessages.Count > 0)
|
||||
// {
|
||||
// //// 在这里调用设备API发送消息
|
||||
// //int sendResult = USB2CAN.CAN_SendMsg(
|
||||
// // _targetCanDevice.DevHandle,
|
||||
// // _targetCanDevice.WriteCANIndex,
|
||||
// // canMessages.ToArray(),
|
||||
// // (uint)canMessages.Count);
|
||||
|
||||
// //if (sendResult < 0)
|
||||
// //{
|
||||
// // LogService.Error($"CAN消息转发失败: 错误码={sendResult}");
|
||||
// //}
|
||||
// //else
|
||||
// //{
|
||||
// // LogService.Debug($"成功转发{sendResult}条CAN消息");
|
||||
// //}
|
||||
// }
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// // 不转发时,清空队列减少内存占用
|
||||
// while (ForwardChannel.Reader.TryRead(out _)) { }
|
||||
// await Task.Delay(10);
|
||||
//}
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// 服务被取消,正常退出
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogService.Error($"消息转发任务异常: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable 实现
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 发送取消信号
|
||||
TaskCancellationTokenSource?.Cancel();
|
||||
|
||||
// 等待任务完成
|
||||
Task.WaitAll(new[] { ProcessTask, ForwardTask }, 1000);
|
||||
}
|
||||
catch { /* 忽略取消异常 */ }
|
||||
finally
|
||||
{
|
||||
// 释放资源
|
||||
TaskCancellationTokenSource?.Dispose();
|
||||
TaskCancellationTokenSource = null;
|
||||
|
||||
// 完成写入器,表示不再接受新数据
|
||||
ReceiveChannel.Writer.Complete();
|
||||
ForwardChannel.Writer.Complete();
|
||||
|
||||
// 清空显示数据
|
||||
App.Current.Dispatcher.Invoke(() => DisplayMessages.Clear());
|
||||
|
||||
|
||||
|
||||
LogService.Info("HightDriveMsgService资源已释放");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user