Files
CapMachine/CapMachine.Wpf/Services/HightDriveMsgService.cs
2025-05-09 16:13:11 +08:00

429 lines
14 KiB
C#
Raw Permalink 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 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()
{
while (await ReceiveChannel.Reader.WaitToReadAsync(TaskCancellationTokenSource.Token))
{
try
{
// 清空列表但保留容量
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
}
}