增加了CAN调度表发送,但是没有测试成功
This commit is contained in:
@@ -5,6 +5,7 @@ using NPOI.OpenXmlFormats.Wordprocessing;
|
||||
using Prism.Ioc;
|
||||
using Prism.Mvvm;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
@@ -549,6 +550,7 @@ namespace CapMachine.Wpf.CanDrive
|
||||
//此时重置NextExecutionTime为当前时间,避免连续的延迟累积
|
||||
// 严重延迟,重新校准
|
||||
NextExecutionTime = Stopwatcher.ElapsedTicks;
|
||||
LogService.Info("定时发送延迟过大,重新校准时间");
|
||||
Console.WriteLine("定时发送延迟过大,重新校准时间");
|
||||
}
|
||||
|
||||
@@ -681,6 +683,180 @@ namespace CapMachine.Wpf.CanDrive
|
||||
#endregion
|
||||
|
||||
|
||||
#region 并行多线程发送报文
|
||||
|
||||
/// <summary>
|
||||
/// 并行精确周期发送CAN数据
|
||||
/// </summary>
|
||||
public void StartParallelPrecisionCycleSendMsg()
|
||||
{
|
||||
// 创建取消标记源
|
||||
var cancellationTokenSource = new CancellationTokenSource();
|
||||
var token = cancellationTokenSource.Token;
|
||||
|
||||
// 保存取消标记,以便在停止时使用
|
||||
CycleSendCts = cancellationTokenSource;
|
||||
|
||||
// 初始化计时基准
|
||||
TicksPerMs = Stopwatch.Frequency / 1000.0;
|
||||
|
||||
// 分组消息,按照消息名称进行分组
|
||||
var groupedMessages = CmdData.GroupBy(x => x.MsgName).ToList();
|
||||
|
||||
// 创建发送任务列表
|
||||
var sendTasks = new List<Task>();
|
||||
|
||||
// 创建线程同步对象,确保DBC操作和发送操作的线程安全
|
||||
object dbcLock = new object();
|
||||
|
||||
// 为每组消息创建单独的发送任务
|
||||
foreach (var messageGroup in groupedMessages)
|
||||
{
|
||||
var msgName = messageGroup.Key;
|
||||
var signals = messageGroup.ToList();
|
||||
|
||||
// 为每个消息组创建一个发送任务
|
||||
var sendTask = Task.Factory.StartNew(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
// 设置线程优先级
|
||||
Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
|
||||
|
||||
// 每个消息使用独立的计时器
|
||||
var messageStopwatch = new Stopwatch();
|
||||
messageStopwatch.Start();
|
||||
|
||||
// 计算该消息的发送周期(可以为不同消息设置不同周期)
|
||||
// 这里可以从配置或参数中获取特定消息的周期
|
||||
long cycleInTicks = (long)(SendCycle * TicksPerMs);
|
||||
long nextExecutionTime = 0;
|
||||
|
||||
while (IsCycleSend && !token.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 计算下一次执行时间
|
||||
nextExecutionTime += cycleInTicks;
|
||||
|
||||
// 获取当前时间
|
||||
long currentTime = messageStopwatch.ElapsedTicks;
|
||||
long delayTicks = nextExecutionTime - currentTime;
|
||||
|
||||
// 精确等待逻辑
|
||||
if (delayTicks > 0)
|
||||
{
|
||||
int delayMs = (int)(delayTicks / TicksPerMs);
|
||||
|
||||
if (delayMs <= 20)
|
||||
{
|
||||
SpinWait.SpinUntil(() => messageStopwatch.ElapsedTicks >= nextExecutionTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Task.Delay(delayMs - 20, token);
|
||||
SpinWait.SpinUntil(() => messageStopwatch.ElapsedTicks >= nextExecutionTime);
|
||||
}
|
||||
}
|
||||
|
||||
// 校准时间,处理严重延迟情况
|
||||
if (messageStopwatch.ElapsedTicks >= nextExecutionTime + cycleInTicks)
|
||||
{
|
||||
nextExecutionTime = messageStopwatch.ElapsedTicks;
|
||||
LogService.Info($"消息{msgName}定时发送延迟过大,重新校准时间");
|
||||
}
|
||||
|
||||
// 使用锁确保DBC操作和发送的线程安全
|
||||
lock (dbcLock)
|
||||
{
|
||||
// 构建CAN消息
|
||||
IntPtr msgPtSend = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CAN.CAN_MSG)));
|
||||
|
||||
try
|
||||
{
|
||||
// 为信号赋值
|
||||
foreach (var signal in signals)
|
||||
{
|
||||
CAN_DBCParser.DBC_SetSignalValue(DBCHandle, new StringBuilder(msgName),
|
||||
new StringBuilder(signal.SignalName), signal.SignalCmdValue);
|
||||
}
|
||||
|
||||
// 同步值到CAN消息
|
||||
CAN_DBCParser.DBC_SyncValueToCANMsg(DBCHandle, new StringBuilder(msgName), msgPtSend);
|
||||
var canMsg = (USB2CAN.CAN_MSG)Marshal.PtrToStructure(msgPtSend, typeof(USB2CAN.CAN_MSG));
|
||||
|
||||
// 直接发送此消息,无需通过队列
|
||||
USB2CAN.CAN_MSG[] canMsgArray = new USB2CAN.CAN_MSG[] { canMsg };
|
||||
int sendedNum = USB2CAN.CAN_SendMsg(DevHandle, WriteCANIndex, canMsgArray, 1);
|
||||
|
||||
// 更新发送状态
|
||||
if (sendedNum >= 0)
|
||||
{
|
||||
// 发送成功
|
||||
IsSendOk = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
IsSendOk = false;
|
||||
LogService.Info($"消息{msgName}发送失败: {sendedNum}");
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 确保释放非托管资源
|
||||
Marshal.FreeHGlobal(msgPtSend);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
LogService.Info($"消息{msgName}发送任务被取消");
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogService.Info($"消息{msgName}发送异常: {ex.Message}");
|
||||
await Task.Delay(10, token);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogService.Info($"消息{msgName}发送线程异常: {ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogService.Info($"消息{msgName}发送线程已退出");
|
||||
}
|
||||
}, token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
|
||||
|
||||
sendTasks.Add(sendTask);
|
||||
}
|
||||
|
||||
// 创建监控任务,监控所有发送任务的状态
|
||||
CycleSendTask = Task.Factory.StartNew(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
// 等待所有任务完成或取消
|
||||
await Task.WhenAll(sendTasks.ToArray());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogService.Info($"并行发送监控任务异常: {ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogService.Info("并行发送任务已全部结束");
|
||||
IsSendOk = false;
|
||||
}
|
||||
}, token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
private bool _IsCycleRevice;
|
||||
/// <summary>
|
||||
/// 是否循环接收数据
|
||||
|
||||
Reference in New Issue
Block a user