增加了CAN调度表发送,但是没有测试成功

This commit is contained in:
2025-08-10 23:49:17 +08:00
parent 7a5793c43a
commit 159187a475
21 changed files with 1618 additions and 29 deletions

View File

@@ -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>
/// 是否循环接收数据

View File

@@ -119,16 +119,24 @@ namespace CapMachine.Wpf.CanDrive
[DllImport("USB2XXX.dll")]
public static extern Int32 CANFD_Init(Int32 DevHandle, Byte CANIndex, ref CANFD_INIT_CONFIG pCanConfig);
[DllImport("USB2XXX.dll")]
public static extern Int32 CANFD_Init2(Int32 DevHandle, Byte CANIndex, Int32 BaudRateNBTBps, Int32 BaudRateDBTBps, Byte EnResistor, Byte ISOCRCEnable);
[DllImport("USB2XXX.dll")]
public static extern Int32 CANFD_StartGetMsg(Int32 DevHandle, Byte CANIndex);
[DllImport("USB2XXX.dll")]
public static extern Int32 CANFD_StopGetMsg(Int32 DevHandle, Byte CANIndex);
[DllImport("USB2XXX.dll")]
public static extern Int32 CANFD_SendMsg(Int32 DevHandle, Byte CANIndex, CANFD_MSG[] pCanSendMsg, Int32 SendMsgNum);
[DllImport("USB2XXX.dll")]
public static extern Int32 CANFD_SendMsgWithTime(Int32 DevHandle, Byte CANIndex, CANFD_MSG[] pCanSendMsg, Int32 SendMsgNum);
[DllImport("USB2XXX.dll")]
public static extern Int32 CANFD_GetMsg(Int32 DevHandle, Byte CANIndex, IntPtr pCanGetMsg, Int32 BufferSize);
[DllImport("USB2XXX.dll")]
public static extern Int32 CANFD_ClearMsg(Int32 DevHandle, Byte CANIndex);
[DllImport("USB2XXX.dll")]
public static extern Int32 CANFD_SetFilter(Int32 DevHandle, Byte CANIndex, ref CANFD_FILTER_CONFIG pCanFilter, Byte Len);
[DllImport("USB2XXX.dll")]
public static extern Int32 CANFD_FilterList_Init(Int32 DevHandle, Byte CANIndex, UInt32[] pIDList, Byte IDListLen);
[DllImport("USB2XXX.dll")]
public static extern Int32 CANFD_GetDiagnostic(Int32 DevHandle, Byte CANIndex, ref CANFD_DIAGNOSTIC pCanDiagnostic);
[DllImport("USB2XXX.dll")]
public static extern Int32 CANFD_GetBusError(Int32 DevHandle, Byte CANIndex, ref CANFD_BUS_ERROR pCanBusError);
@@ -139,7 +147,13 @@ namespace CapMachine.Wpf.CanDrive
[DllImport("USB2XXX.dll")]
public static extern Int32 CANFD_StartSchedule(Int32 DevHandle, Byte CANIndex, Byte MsgTabIndex, Byte TimePrecMs, Byte OrderSend);
[DllImport("USB2XXX.dll")]
public static extern Int32 CANFD_UpdateSchedule(Int32 DevHandle, Byte CANIndex, Byte MsgTabIndex, Byte MsgIndex, CANFD_MSG[] pCanMsg, Byte MsgNum);
[DllImport("USB2XXX.dll")]
public static extern Int32 CANFD_StopSchedule(Int32 DevHandle, Byte CANIndex);
[DllImport("USB2XXX.dll")]
public static extern Int64 CANFD_GetStartTime(Int32 DevHandle, Byte CANIndex);
[DllImport("USB2XXX.dll")]
public static extern Int32 CANFD_ResetStartTime(Int32 DevHandle, Byte CANIndex);
[DllImport("USB2XXX.dll")]
public static extern Int32 CANFD_SetRelay(Int32 DevHandle, Byte RelayState);