diff --git a/.editorconfig b/.editorconfig
index cb53e99..a20d564 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -2,3 +2,126 @@
# CA1416: 验证平台兼容性
dotnet_diagnostic.CA1416.severity = silent
+
+[*.cs]
+#### 命名样式 ####
+
+# 命名规则
+
+dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
+dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
+dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
+
+dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.types_should_be_pascal_case.symbols = types
+dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
+
+dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
+dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
+
+# 符号规范
+
+dotnet_naming_symbols.interface.applicable_kinds = interface
+dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.interface.required_modifiers =
+
+dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
+dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.types.required_modifiers =
+
+dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
+dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.non_field_members.required_modifiers =
+
+# 命名样式
+
+dotnet_naming_style.begins_with_i.required_prefix = I
+dotnet_naming_style.begins_with_i.required_suffix =
+dotnet_naming_style.begins_with_i.word_separator =
+dotnet_naming_style.begins_with_i.capitalization = pascal_case
+
+dotnet_naming_style.pascal_case.required_prefix =
+dotnet_naming_style.pascal_case.required_suffix =
+dotnet_naming_style.pascal_case.word_separator =
+dotnet_naming_style.pascal_case.capitalization = pascal_case
+
+dotnet_naming_style.pascal_case.required_prefix =
+dotnet_naming_style.pascal_case.required_suffix =
+dotnet_naming_style.pascal_case.word_separator =
+dotnet_naming_style.pascal_case.capitalization = pascal_case
+csharp_using_directive_placement = outside_namespace:silent
+csharp_style_expression_bodied_methods = false:silent
+csharp_style_expression_bodied_constructors = false:silent
+csharp_style_expression_bodied_operators = false:silent
+csharp_style_expression_bodied_properties = true:silent
+csharp_style_expression_bodied_indexers = true:silent
+csharp_style_expression_bodied_accessors = true:silent
+csharp_style_expression_bodied_lambdas = true:silent
+csharp_style_expression_bodied_local_functions = false:silent
+csharp_style_conditional_delegate_call = true:suggestion
+csharp_style_var_for_built_in_types = false:silent
+csharp_style_var_when_type_is_apparent = false:silent
+csharp_style_var_elsewhere = false:silent
+csharp_prefer_simple_using_statement = true:suggestion
+csharp_prefer_braces = true:silent
+csharp_style_namespace_declarations = block_scoped:silent
+csharp_style_prefer_method_group_conversion = true:silent
+csharp_style_prefer_top_level_statements = true:silent
+csharp_style_prefer_primary_constructors = true:suggestion
+csharp_prefer_system_threading_lock = true:suggestion
+
+[*.vb]
+#### 命名样式 ####
+
+# 命名规则
+
+dotnet_naming_rule.interface_should_be_以_i_开始.severity = suggestion
+dotnet_naming_rule.interface_should_be_以_i_开始.symbols = interface
+dotnet_naming_rule.interface_should_be_以_i_开始.style = 以_i_开始
+
+dotnet_naming_rule.类型_should_be_帕斯卡拼写法.severity = suggestion
+dotnet_naming_rule.类型_should_be_帕斯卡拼写法.symbols = 类型
+dotnet_naming_rule.类型_should_be_帕斯卡拼写法.style = 帕斯卡拼写法
+
+dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.severity = suggestion
+dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.symbols = 非字段成员
+dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.style = 帕斯卡拼写法
+
+# 符号规范
+
+dotnet_naming_symbols.interface.applicable_kinds = interface
+dotnet_naming_symbols.interface.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
+dotnet_naming_symbols.interface.required_modifiers =
+
+dotnet_naming_symbols.类型.applicable_kinds = class, struct, interface, enum
+dotnet_naming_symbols.类型.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
+dotnet_naming_symbols.类型.required_modifiers =
+
+dotnet_naming_symbols.非字段成员.applicable_kinds = property, event, method
+dotnet_naming_symbols.非字段成员.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
+dotnet_naming_symbols.非字段成员.required_modifiers =
+
+# 命名样式
+
+dotnet_naming_style.以_i_开始.required_prefix = I
+dotnet_naming_style.以_i_开始.required_suffix =
+dotnet_naming_style.以_i_开始.word_separator =
+dotnet_naming_style.以_i_开始.capitalization = pascal_case
+
+dotnet_naming_style.帕斯卡拼写法.required_prefix =
+dotnet_naming_style.帕斯卡拼写法.required_suffix =
+dotnet_naming_style.帕斯卡拼写法.word_separator =
+dotnet_naming_style.帕斯卡拼写法.capitalization = pascal_case
+
+dotnet_naming_style.帕斯卡拼写法.required_prefix =
+dotnet_naming_style.帕斯卡拼写法.required_suffix =
+dotnet_naming_style.帕斯卡拼写法.word_separator =
+dotnet_naming_style.帕斯卡拼写法.capitalization = pascal_case
+
+[*.{cs,vb}]
+end_of_line = crlf
+dotnet_style_qualification_for_field = false:silent
+dotnet_style_qualification_for_property = false:silent
+dotnet_style_qualification_for_method = false:silent
+dotnet_style_qualification_for_event = false:silent
\ No newline at end of file
diff --git a/CapMachine.Model/CANLIN/CANConfigExd.cs b/CapMachine.Model/CANLIN/CANConfigExd.cs
index 7213492..d44149b 100644
--- a/CapMachine.Model/CANLIN/CANConfigExd.cs
+++ b/CapMachine.Model/CANLIN/CANConfigExd.cs
@@ -38,6 +38,11 @@ namespace CapMachine.Model.CANLIN
[Column(Name = "DbcPath", IsNullable = false, StringLength = 500)]
public string? DbcPath { get; set; }
+ ///
+ /// 调度表是否启用
+ ///
+ [Column(Name = "SchEnable")]
+ public bool SchEnable { get; set; }
/////
diff --git a/CapMachine.Model/CANLIN/CANScheduleConfig.cs b/CapMachine.Model/CANLIN/CANScheduleConfig.cs
new file mode 100644
index 0000000..5ea3d66
--- /dev/null
+++ b/CapMachine.Model/CANLIN/CANScheduleConfig.cs
@@ -0,0 +1,55 @@
+using FreeSql.DataAnnotations;
+
+namespace CapMachine.Model.CANLIN
+{
+ ///
+ /// 调度表的配置
+ /// 其实这些调度表是在DBC中有的,但是图莫斯的驱动没有读取到这些信息
+ /// 那么我们在系统层面进行操作和保存这些信息
+ ///
+ [Table(Name = "CANScheduleConfig")]
+ public class CANScheduleConfig
+ {
+ ///
+ /// 主键
+ ///
+ [Column(IsPrimary = true, IsIdentity = true)]
+ public long Id { get; set; }
+
+ ///
+ /// 消息名称
+ ///
+ [Column(Name = "MsgName")]
+ public string? MsgName { get; set; }
+
+ ///
+ /// 消息的周期
+ ///
+ [Column(Name = "Cycle")]
+ public int Cycle { get; set; }
+
+ ///
+ /// 发送方式
+ ///
+ [Column(Name = "OrderSend")]
+ public int OrderSend { get; set; }
+
+ ///
+ /// 调度表的Index
+ /// //约定每帧对应一个调度表,预设5个调度表,每个调度表对应一个帧
+ /// 0-4这个范围的设置Index
+ ///
+ [Column(Name = "SchTabIndex")]
+ public int SchTabIndex { get; set; }
+
+
+
+
+ ///
+ /// ///////////////////////////////////////////导航属性///////////////////////////////////////////////////////
+ ///
+
+ public long CanLinConfigProId { get; set; }
+ public CanLinConfigPro? CanLinConfigPro { get; set; }
+ }
+}
diff --git a/CapMachine.Model/CANLIN/CanLinConfigPro.cs b/CapMachine.Model/CANLIN/CanLinConfigPro.cs
index 9f3b9ad..eb5521d 100644
--- a/CapMachine.Model/CANLIN/CanLinConfigPro.cs
+++ b/CapMachine.Model/CANLIN/CanLinConfigPro.cs
@@ -44,6 +44,12 @@ namespace CapMachine.Model.CANLIN
public List? CanLinConfigContents { get; set; }
+ ///
+ /// ///////////////////////////////////////////导航属性///////////////////////////////////////////////////////
+ ///
+ ///CAN 的调度表配置模式
+ public List? CanScheduleConfigs { get; set; }
+
///
/// ///////////////////////////////////////////导航属性 LIN 一对一///////////////////////////////////////////////////////
diff --git a/CapMachine.Wpf/App.xaml.cs b/CapMachine.Wpf/App.xaml.cs
index 8c8127f..4037639 100644
--- a/CapMachine.Wpf/App.xaml.cs
+++ b/CapMachine.Wpf/App.xaml.cs
@@ -200,7 +200,8 @@ namespace CapMachine.Wpf
containerRegistry.RegisterDialog();
containerRegistry.RegisterDialog();
containerRegistry.RegisterDialog();
-
+ containerRegistry.RegisterDialog();
+
containerRegistry.RegisterDialog();
diff --git a/CapMachine.Wpf/CanDrive/CanFD/ToomossCanFD.cs b/CapMachine.Wpf/CanDrive/CanFD/ToomossCanFD.cs
index 2e4fbc6..cfb708a 100644
--- a/CapMachine.Wpf/CanDrive/CanFD/ToomossCanFD.cs
+++ b/CapMachine.Wpf/CanDrive/CanFD/ToomossCanFD.cs
@@ -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 并行多线程发送报文
+
+ ///
+ /// 并行精确周期发送CAN数据
+ ///
+ 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();
+
+ // 创建线程同步对象,确保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;
///
/// 是否循环接收数据
diff --git a/CapMachine.Wpf/CanDrive/CanFD/USB2CANFD.cs b/CapMachine.Wpf/CanDrive/CanFD/USB2CANFD.cs
index 67a278e..fd1b13c 100644
--- a/CapMachine.Wpf/CanDrive/CanFD/USB2CANFD.cs
+++ b/CapMachine.Wpf/CanDrive/CanFD/USB2CANFD.cs
@@ -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);
diff --git a/CapMachine.Wpf/CanDrive/ToomossCan.cs b/CapMachine.Wpf/CanDrive/ToomossCan.cs
index 6b9082f..5bbe60f 100644
--- a/CapMachine.Wpf/CanDrive/ToomossCan.cs
+++ b/CapMachine.Wpf/CanDrive/ToomossCan.cs
@@ -1,6 +1,10 @@
-using CapMachine.Wpf.Models.Tag;
+using CapMachine.Core;
+using CapMachine.Model.CANLIN;
+using CapMachine.Wpf.Dtos;
+using CapMachine.Wpf.Models.Tag;
using CapMachine.Wpf.Services;
using HslCommunication;
+using ImTools;
using NLog;
using NPOI.OpenXmlFormats.Wordprocessing;
using Prism.Ioc;
@@ -35,7 +39,7 @@ namespace CapMachine.Wpf.CanDrive
ContainerProvider = containerProvider;
HighSpeedDataService = ContainerProvider.Resolve();
LoggerService = ContainerProvider.Resolve();
-
+
//Stopwatch.Frequency表示高精度计时器每秒的计数次数(ticks/秒)每毫秒的ticks数 = 每秒的ticks数 ÷ 1000
TicksPerMs = Stopwatch.Frequency / 1000.0;
}
@@ -488,8 +492,13 @@ namespace CapMachine.Wpf.CanDrive
///
private static Task CycleSendTask { get; set; }
+ ///
+ /// 定时扫描更新数据 扫描Task
+ ///
+ private static Task CycleUpdateCmdTask { get; set; }
+
StringBuilder ValueSb = new StringBuilder(16);
- double[] ValueDouble=new double[5];
+ double[] ValueDouble = new double[5];
private bool _IsSendOk;
///
@@ -785,6 +794,296 @@ namespace CapMachine.Wpf.CanDrive
#endregion
+ #region 调度表发送报文
+
+ private bool _SchEnable;
+ ///
+ /// 调度表使能
+ ///
+ public bool SchEnable
+ {
+ get { return _SchEnable; }
+ set
+ {
+ _SchEnable = value;
+ RaisePropertyChanged();
+ }
+ }
+
+
+ ///
+ /// 调度表的发送的报文数据
+ ///
+ private USB2CAN.CAN_MSG[] SchCanMsg { get; set; }
+
+ ///
+ /// 依据消息的分组
+ ///
+ private IEnumerable> GroupMsg { get; set; }
+
+ ///
+ /// 调度表集合数据
+ /// 总共3个调度表,第一个表里面包含3帧数据,第二个调度表包含6帧数据,第三个调度表包含11帧数据
+ /// Byte[] MsgTabNum = new Byte[3] { 3, 6, 11 };
+ ///
+ private Byte[] MsgTabNum { get; set; }
+
+ ///
+ /// 调度表发送的次数集合
+ /// 第一个调度表循环发送数据,第二个调度表循环发送数据,第三个调度表只发送3次
+ /// UInt16[] SendTimes = new UInt16[3] { 0xFFFF, 0xFFFF, 3 };
+ ///
+ private UInt16[] SendTimes { get; set; }
+
+ ///
+ /// 预设的调度表的个数 常值
+ ///
+ private const int MsgTabCount = 5;
+
+ ///
+ /// 定时更新时间
+ ///
+ private int UpdateCycle = 500;
+
+ ///
+ /// CNA 调度表的配置信息
+ ///
+ public List ListCANScheduleConfig { get; set; }
+
+ Random random = new Random();
+
+ ///
+ /// 更新数据
+ ///
+ public void UpdateValue()
+ {
+ //通过DBC进行对消息赋值
+ IntPtr msgPtSend = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CAN.CAN_MSG)));
+ int Index = 0;
+ //循环给MSG赋值数据
+ foreach (var itemMsg in GroupMsg)
+ {
+ foreach (var itemSignal in itemMsg)
+ {
+ itemSignal.SignalCmdValue = random.Next(0, 100);
+ CAN_DBCParser.DBC_SetSignalValue(DBCHandle, new StringBuilder(itemMsg.Key), new StringBuilder(itemSignal.SignalName), itemSignal.SignalCmdValue);
+ }
+ CAN_DBCParser.DBC_SyncValueToCANMsg(DBCHandle, new StringBuilder(itemMsg.Key), msgPtSend);
+ SchCanMsg[Index] = (USB2CAN.CAN_MSG)Marshal.PtrToStructure(msgPtSend, typeof(USB2CAN.CAN_MSG));
+ Index++;
+ }
+
+ //通过DBC写入数据后生成CanMsg
+ //将信号值填入CAN消息里面
+
+ //释放申请的临时缓冲区
+ Marshal.FreeHGlobal(msgPtSend);
+
+
+ ////总共3个调度表,第一个表里面包含3帧数据,第二个调度表包含6帧数据,第三个调度表包含11帧数据
+ //MsgTabNum = new Byte[1] { 1 };
+ ////第一个调度表循环发送数据,第二个调度表循环发送数据,第三个调度表只发送3次
+ //SendTimes = new UInt16[1] { 0xFFFF };
+ //var ret = USB2CAN.CAN_SetSchedule(DevHandle, WriteCANIndex, SchCanMsg, MsgTabNum, SendTimes, 1);//配置调度表,该函数耗时可能会比较长,但是只需要执行一次即可
+ var ret = USB2CAN.CAN_UpdateSchedule(DevHandle, WriteCANIndex, 0, 0, SchCanMsg, 1);//配置调度表,该函数耗时可能会比较长,但是只需要执行一次即可
+ if (ret == USB2CAN.CAN_SUCCESS)
+ {
+ Console.WriteLine("Update CAN Schedule Success");
+ }
+ else
+ {
+ Console.WriteLine("Update CAN Schedule Error ret = {0}", ret);
+ return;
+ }
+ }
+
+ ///
+ /// 开始调度表执行
+ ///
+ public void StartSchedule()
+ {
+ if (CmdData.Count() == 0) return;
+
+ //依据报文进行分组
+ GroupMsg = CmdData.GroupBy(x => x.MsgName)!;
+ //初始化调度表要发送的消息结构
+ SchCanMsg = new USB2CAN.CAN_MSG[GroupMsg.Count()];
+ for (int i = 0; i < GroupMsg.Count(); i++)
+ {
+ SchCanMsg[i] = new USB2CAN.CAN_MSG();
+ SchCanMsg[i].Data = new Byte[64];
+ }
+
+ //通过DBC进行对消息赋值
+ IntPtr msgPtSend = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CAN.CAN_MSG)));
+ int Index = 0;
+ //循环给MSG赋值数据
+ foreach (var itemMsg in GroupMsg)
+ {
+ foreach (var itemSignal in itemMsg)
+ {
+ CAN_DBCParser.DBC_SetSignalValue(DBCHandle, new StringBuilder(itemMsg.Key), new StringBuilder(itemSignal.SignalName), itemSignal.SignalCmdValue);
+ }
+ CAN_DBCParser.DBC_SyncValueToCANMsg(DBCHandle, new StringBuilder(itemMsg.Key), msgPtSend);
+ //每个分组就是一个帧指令/消息数据
+ SchCanMsg[Index] = (USB2CAN.CAN_MSG)Marshal.PtrToStructure(msgPtSend, typeof(USB2CAN.CAN_MSG));
+ //分配当前消息帧在集合中的位置信息到ListCANScheduleConfig中,方便实时更新时定位帧的位置
+ if (ListCANScheduleConfig.Any(a=>a.MsgName== itemMsg.Key))
+ {
+ //把帧的位置给ListCANScheduleConfig,方便更新时定位数据
+ ListCANScheduleConfig.FindFirst(a => a.MsgName == itemMsg.Key).MsgIndex = Index;
+ }
+ Index++;
+ }
+ //通过DBC写入数据后生成CanMsg
+ //将信号值填入CAN消息里面
+ //释放申请的临时缓冲区
+ Marshal.FreeHGlobal(msgPtSend);
+
+
+ //Sample:总共3个调度表,第一个表里面包含3帧数据,第二个调度表包含6帧数据,第三个调度表包含11帧数据
+ //约定每帧对应一个调度表,预设5个调度表,每个调度表对应一个帧
+ MsgTabNum = new Byte[MsgTabCount] { 1, 1, 1, 1, 1 };
+ //0xFFFF:调度表循环发送数据,X:调度表循环发送的次数
+ //设置每个调度表的发送方式,约定全部为循环发送
+ SendTimes = new UInt16[MsgTabCount] { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF };
+
+ //SchCanMsg:需要发送的消息集合;MsgTabNum:调度表集合数据;SendTimes:发送次数集合数据;调度表个数:MsgTabCount
+ var ret = USB2CAN.CAN_SetSchedule(DevHandle, WriteCANIndex, SchCanMsg, MsgTabNum, SendTimes, MsgTabCount);//配置调度表,该函数耗时可能会比较长,但是只需要执行一次即可
+ if (ret == USB2CAN.CAN_SUCCESS)
+ {
+ Console.WriteLine("Set CAN Schedule Success");
+ }
+ else
+ {
+ Console.WriteLine("Set CAN Schedule Error ret = {0}", ret);
+ LoggerService.Info($"Set CAN Schedule Error; 返回错误代码:{ret}");
+ return;
+ }
+
+ foreach (var itemGroupMsg in GroupMsg)
+ {
+ if (itemGroupMsg == null) continue;
+ if (ListCANScheduleConfig.Any(a => a.MsgName!.Contains(itemGroupMsg.Key)))
+ {
+ var CANScheduleConfig = ListCANScheduleConfig.FindFirst(a => a.MsgName!.Contains(itemGroupMsg.Key));
+ //配置表里面包括这个报文消息内容
+ ret = USB2CAN.CAN_StartSchedule(DevHandle, WriteCANIndex, (byte)CANScheduleConfig.SchTabIndex, (byte)CANScheduleConfig.Cycle, (byte)CANScheduleConfig.OrderSend);
+ if (ret == USB2CAN.CAN_SUCCESS)
+ {
+ Console.WriteLine($"Start CAN Schedule 1 Success,SchTabIndex:{(byte)CANScheduleConfig.SchTabIndex}-Cycle:{(byte)CANScheduleConfig.Cycle}-OrderSend:{(byte)CANScheduleConfig.OrderSend}");
+ }
+ else
+ {
+ Console.WriteLine("Start CAN Schedule 1 Error ret = {0}", ret);
+ LoggerService.Info($"Start CAN Schedule 1 Error;消息名称:{CANScheduleConfig.MsgName}");
+ return;
+ }
+ }
+ else
+ {
+ LoggerService.Info($"调度表配置未发现对应的消息报文信息;报文信息{itemGroupMsg.Key}");
+ }
+ }
+
+ //走到这里说明调度表执行的是OK的
+ IsSendOk = true;
+
+ }
+
+
+ ///
+ /// 停止调度表
+ ///
+ public void StopSchedule()
+ {
+ ret = USB2CAN.CAN_StopSchedule(DevHandle, WriteCANIndex);//启动第一个调度表,表里面的CAN帧并行发送
+ if (ret == USB2CAN.CAN_SUCCESS)
+ {
+ Console.WriteLine("Stop CAN Schedule");
+ LoggerService.Info($"Stop CAN Schedule");
+ }
+ else
+ {
+ Console.WriteLine("Start CAN Schedule Error ret = {0}", ret);
+ LoggerService.Info($"Stop CAN Schedule");
+ return;
+ }
+ }
+
+ ///
+ /// 循环使用的
+ ///
+ private int CycleUpdateIndex = 0;
+
+ ///
+ /// 循环更新调度表的指令数据
+ /// 定时更新数据到调度表中
+ ///
+ public void StartCycleUpdateCmd()
+ {
+ CycleUpdateCmdTask = Task.Run(async () =>
+ {
+ while (IsCycleSend)
+ {
+ await Task.Delay(UpdateCycle);
+ try
+ {
+ //通过DBC进行对消息赋值
+ IntPtr msgPtSend = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CAN.CAN_MSG)));
+ CycleUpdateIndex = 0;
+ //循环给MSG赋值数据,顺序是固定的,跟初始时设置是一样的
+ foreach (var itemMsg in GroupMsg)
+ {
+ foreach (var itemSignal in itemMsg)
+ {
+ itemSignal.SignalCmdValue = random.Next(0, 100); //仿真测试数据使用
+ CAN_DBCParser.DBC_SetSignalValue(DBCHandle, new StringBuilder(itemMsg.Key), new StringBuilder(itemSignal.SignalName), itemSignal.SignalCmdValue);
+ }
+ CAN_DBCParser.DBC_SyncValueToCANMsg(DBCHandle, new StringBuilder(itemMsg.Key), msgPtSend);
+ SchCanMsg[CycleUpdateIndex] = (USB2CAN.CAN_MSG)Marshal.PtrToStructure(msgPtSend, typeof(USB2CAN.CAN_MSG));
+ CycleUpdateIndex++;
+ }
+
+ //通过DBC写入数据后生成CanMsg
+ //将信号值填入CAN消息里面
+
+ //释放申请的临时缓冲区
+ Marshal.FreeHGlobal(msgPtSend);
+
+ //配置信息
+ foreach (var itemMsgSchConfig in ListCANScheduleConfig)
+ {
+ //USB2CAN.CAN_MSG[] SchCanMsg1=new CAN_MSG[1];
+ //SchCanMsg1[0] = SchCanMsg[itemMsgSchConfig.MsgIndex];
+
+ // MsgTabIndex CAN调度表索引号 ;MsgIndex 开始更新帧起始索引,若起始索引大于调度表帧数,则将帧添加到调度表后面, ;
+ // pCanMsg 需要更新的CAN帧指针,消息数据 ; MsgNum pCanMsgTab里面包含的有效帧数,一个调度表对应一个帧/消息,即为:1 (byte)(itemMsgSchConfig.MsgIndex+0)
+ var ret = USB2CAN.CAN_UpdateSchedule(DevHandle, WriteCANIndex, (byte)(itemMsgSchConfig.SchTabIndex+0), (byte)0, SchCanMsg, 1);//配置调度表,该函数耗时可能会比较长,但是只需要执行一次即可
+ if (ret == USB2CAN.CAN_SUCCESS)
+ {
+ Console.WriteLine($"Update CAN Schedule Success--SchTabIndex:{(byte)itemMsgSchConfig.SchTabIndex} --MsgIndex:{(byte)(itemMsgSchConfig.MsgIndex)} ");
+ }
+ else
+ {
+ Console.WriteLine($"Update CAN Schedule Error ret = {ret}---SchTabIndex:{(byte)itemMsgSchConfig.SchTabIndex} --MsgIndex:{(byte)(itemMsgSchConfig.MsgIndex)}");
+ //return;
+ }
+
+ }
+
+
+ }
+ catch (Exception ex)
+ {
+ LoggerService.Info($"时间:{DateTime.Now.ToString()}-【MSG】-{ex.Message}");
+ }
+ }
+ });
+ }
+
+
+ #endregion
///
/// 循环获取CAN消息
@@ -802,24 +1101,25 @@ namespace CapMachine.Wpf.CanDrive
USB2CAN.CAN_MSG[] CanMsgBuffer = new USB2CAN.CAN_MSG[128];
//申请数据缓冲区
IntPtr msgPtRead = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CAN.CAN_MSG)) * CanMsgBuffer.Length);
- int CanNum = USB2CAN.CAN_GetMsgWithSize(DevHandle, ReadCANIndex, msgPtRead, CanMsgBuffer.Length);
+ //int CanNum = USB2CAN.CAN_GetMsgWithSize(DevHandle, ReadCANIndex, msgPtRead, CanMsgBuffer.Length);
+ int CanNum = USB2CAN.CAN_GetMsgWithSize(DevHandle, 1, msgPtRead, CanMsgBuffer.Length);
if (CanNum > 0)
{
IsReviceOk = true;
- Console.WriteLine("Read CanMsgNum = {0}", CanNum);
+ //Console.WriteLine("Read CanMsgNum = {0}", CanNum);
for (int i = 0; i < CanNum; i++)
{
//CanMsgBuffer[i] = (USB2CAN.CAN_MSG)Marshal.PtrToStructure((IntPtr)((UInt32)msgPtRead + i * Marshal.SizeOf(typeof(USB2CAN.CAN_MSG))), typeof(USB2CAN.CAN_MSG)); //有溢出报错
CanMsgBuffer[i] = (USB2CAN.CAN_MSG)Marshal.PtrToStructure((IntPtr)(msgPtRead + i * Marshal.SizeOf(typeof(USB2CAN.CAN_MSG))), typeof(USB2CAN.CAN_MSG));
- Console.WriteLine("CanMsg[{0}].ID = 0x{1}", i, CanMsgBuffer[i].ID.ToString("X8"));
- Console.WriteLine("CanMsg[{0}].TimeStamp = {1}", i, CanMsgBuffer[i].TimeStamp);
- Console.Write("CanMsg[{0}].Data = ", i);
- for (int j = 0; j < CanMsgBuffer[i].DataLen; j++)
- {
- Console.Write("{0} ", CanMsgBuffer[i].Data[j].ToString("X2"));
- }
- Console.WriteLine("");
+ //Console.WriteLine("CanMsg[{0}].ID = 0x{1}", i, CanMsgBuffer[i].ID.ToString("X8"));
+ //Console.WriteLine("CanMsg[{0}].TimeStamp = {1}", i, CanMsgBuffer[i].TimeStamp);
+ //Console.Write("CanMsg[{0}].Data = ", i);
+ //for (int j = 0; j < CanMsgBuffer[i].DataLen; j++)
+ //{
+ // Console.Write("{0} ", CanMsgBuffer[i].Data[j].ToString("X2"));
+ //}
+ //Console.WriteLine("");
//报文给高速记录的服务
HighSpeedDataService.AppendOrUpdateMsg(new Models.HighSpeed.CommMsg()
@@ -833,7 +1133,7 @@ namespace CapMachine.Wpf.CanDrive
}
else if (CanNum == 0)
{
- IsReviceOk=false;
+ IsReviceOk = false;
Console.WriteLine("No CAN data!");
}
else
@@ -841,7 +1141,7 @@ namespace CapMachine.Wpf.CanDrive
IsReviceOk = false;
Console.WriteLine("Get CAN data error!");
}
- Console.WriteLine("");
+ //Console.WriteLine("");
//将CAN消息数据填充到信号里面,用DBC解析数据
CAN_DBCParser.DBC_SyncCANMsgToValue(DBCHandle, msgPtRead, CanNum);
diff --git a/CapMachine.Wpf/CanDrive/usb2can.cs b/CapMachine.Wpf/CanDrive/usb2can.cs
index 672bc5c..427625a 100644
--- a/CapMachine.Wpf/CanDrive/usb2can.cs
+++ b/CapMachine.Wpf/CanDrive/usb2can.cs
@@ -101,14 +101,22 @@ namespace CapMachine.Wpf.CanDrive
[DllImport("USB2XXX.dll")]
public static extern Int32 CAN_Init(Int32 DevHandle, Byte CANIndex, ref CAN_INIT_CONFIG pCanConfig);
[DllImport("USB2XXX.dll")]
+ public static extern Int32 CAN_Init2(Int32 DevHandle, Byte CANIndex, Int32 BaudRateBps, Byte EnResistor);
+ [DllImport("USB2XXX.dll")]
public static extern Int32 CAN_Filter_Init(Int32 DevHandle, Byte CANIndex, ref CAN_FILTER_CONFIG pFilterConfig);
[DllImport("USB2XXX.dll")]
+ public static extern Int32 CAN_FilterList_Init(Int32 DevHandle, Byte CANIndex, UInt32[] pIDList, Byte IDListLen);
+ [DllImport("USB2XXX.dll")]
public static extern Int32 CAN_StartGetMsg(Int32 DevHandle, Byte CANIndex);
[DllImport("USB2XXX.dll")]
public static extern Int32 CAN_StopGetMsg(Int32 DevHandle, Byte CANIndex);
[DllImport("USB2XXX.dll")]
public static extern Int32 CAN_SendMsg(Int32 DevHandle, Byte CANIndex, CAN_MSG[] pCanSendMsg, UInt32 SendMsgNum);
[DllImport("USB2XXX.dll")]
+ public static extern Int32 CAN_SendMsgSynch(Int32 DevHandle, Byte CANIndex, CAN_MSG[] pCanSendMsg, UInt32 SendMsgNum);
+ [DllImport("USB2XXX.dll")]
+ public static extern Int32 CAN_SendMsgWithTime(Int32 DevHandle, Byte CANIndex, CAN_MSG[] pCanSendMsg, UInt32 SendMsgNum);
+ [DllImport("USB2XXX.dll")]
public static extern Int32 CAN_GetMsg(Int32 DevHandle, Byte CANIndex, IntPtr pCanGetMsg);
[DllImport("USB2XXX.dll")]
public static extern Int32 CAN_GetMsgWithSize(Int32 DevHandle, Byte CANIndex, IntPtr pCanGetMsg, Int32 BufferSize);
@@ -121,9 +129,17 @@ namespace CapMachine.Wpf.CanDrive
[DllImport("USB2XXX.dll")]
public static extern Int32 CAN_StartSchedule(Int32 DevHandle, Byte CANIndex, Byte MsgTabIndex, Byte TimePrecMs, Byte OrderSend);
[DllImport("USB2XXX.dll")]
+ public static extern Int32 CAN_UpdateSchedule(Int32 DevHandle, Byte CANIndex, Byte MsgTabIndex, Byte MsgIndex, CAN_MSG[] pCanMsg, Byte MsgNum);
+ [DllImport("USB2XXX.dll")]
public static extern Int32 CAN_StopSchedule(Int32 DevHandle, Byte CANIndex);
[DllImport("USB2XXX.dll")]
public static extern Int32 CAN_SetRelay(Int32 DevHandle, Byte RelayState);
+ [DllImport("USB2XXX.dll")]
+ public static extern Int32 CAN_Stop(Int32 DevHandle, Byte CANIndex);
+ [DllImport("USB2XXX.dll")]
+ public static extern Int64 CAN_GetStartTime(Int32 DevHandle, Byte CANIndex);
+ [DllImport("USB2XXX.dll")]
+ public static extern Int32 CAN_ResetStartTime(Int32 DevHandle, Byte CANIndex);
//CAN Bootloader相关函数
[DllImport("USB2XXX.dll")]
diff --git a/CapMachine.Wpf/CapMachine.Wpf.csproj b/CapMachine.Wpf/CapMachine.Wpf.csproj
index 38d28f8..16f359b 100644
--- a/CapMachine.Wpf/CapMachine.Wpf.csproj
+++ b/CapMachine.Wpf/CapMachine.Wpf.csproj
@@ -1,7 +1,7 @@
- WinExe
+ Exe
net6.0-windows
enable
enable
diff --git a/CapMachine.Wpf/Dtos/CANConfigExdDto.cs b/CapMachine.Wpf/Dtos/CANConfigExdDto.cs
index 7018cf1..2dc82df 100644
--- a/CapMachine.Wpf/Dtos/CANConfigExdDto.cs
+++ b/CapMachine.Wpf/Dtos/CANConfigExdDto.cs
@@ -43,5 +43,15 @@ namespace CapMachine.Wpf.Dtos
get { return _DbcPath; }
set { _DbcPath = value; RaisePropertyChanged(); }
}
+
+ private bool _SchEnable;
+ ///
+ /// 调度表是否启用
+ ///
+ public bool SchEnable
+ {
+ get { return _SchEnable; }
+ set { _SchEnable = value; RaisePropertyChanged(); }
+ }
}
}
diff --git a/CapMachine.Wpf/Dtos/CANMsgDto.cs b/CapMachine.Wpf/Dtos/CANMsgDto.cs
new file mode 100644
index 0000000..40db5bc
--- /dev/null
+++ b/CapMachine.Wpf/Dtos/CANMsgDto.cs
@@ -0,0 +1,27 @@
+using Prism.Mvvm;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CapMachine.Wpf.Dtos
+{
+ ///
+ /// CAN报文和帧
+ ///
+ public class CANMsgDto:BindableBase
+ {
+
+ private string? _MsgName;
+ ///
+ /// 消息名称/帧名称
+ ///
+ public string? MsgName
+ {
+ get { return _MsgName; }
+ set { _MsgName = value; RaisePropertyChanged(); }
+ }
+
+ }
+}
diff --git a/CapMachine.Wpf/Dtos/CANScheduleConfigDto.cs b/CapMachine.Wpf/Dtos/CANScheduleConfigDto.cs
new file mode 100644
index 0000000..c19970f
--- /dev/null
+++ b/CapMachine.Wpf/Dtos/CANScheduleConfigDto.cs
@@ -0,0 +1,83 @@
+using CapMachine.Model.CANLIN;
+using Prism.Mvvm;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CapMachine.Wpf.Dtos
+{
+ ///
+ /// CANScheduleConfigDto
+ ///
+ public class CANScheduleConfigDto : BindableBase
+ {
+ ///
+ /// 主键
+ ///
+ public long Id { get; set; }
+
+ private string? _MsgName;
+ ///
+ /// 消息名称/帧名称
+ ///
+ public string? MsgName
+ {
+ get { return _MsgName; }
+ set { _MsgName = value; RaisePropertyChanged(); }
+ }
+
+ private int _Cycle;
+ ///
+ /// 周期
+ ///
+ public int Cycle
+ {
+ get { return _Cycle; }
+ set { _Cycle = value; RaisePropertyChanged(); }
+ }
+
+ private int _OrderSend;
+ ///
+ /// 发送方式
+ ///
+ public int OrderSend
+ {
+ get { return _OrderSend; }
+ set { _OrderSend = value; RaisePropertyChanged(); }
+ }
+
+ private int _SchTabIndex;
+ ///
+ /// 调度表的Index序列
+ ///
+ public int SchTabIndex
+ {
+ get { return _SchTabIndex; }
+ set { _SchTabIndex = value; RaisePropertyChanged(); }
+ }
+
+ ///
+ /// 在更新调度表数据时,我们有一个整体的帧数据指令集合,但是这些帧数据集合,分属于不同的调度表,
+ /// 这个在开始时生成整体的帧数据指令集合才会把这个MsgIndex分配上,这个不需要保存到数据库中,对接使用
+ ///
+ public int MsgIndex { get; set; }
+
+ ///
+ /// 程序的ID
+ ///
+ public long CanLinConfigProId { get; set; }
+
+
+ private CanLinConfigPro _CanLinConfigPro;
+ ///
+ /// 所属的程序
+ ///
+ public CanLinConfigPro CanLinConfigPro
+ {
+ get { return _CanLinConfigPro; }
+ set { _CanLinConfigPro = value; RaisePropertyChanged(); }
+ }
+ }
+}
diff --git a/CapMachine.Wpf/LinDrive/ToomossLin.cs b/CapMachine.Wpf/LinDrive/ToomossLin.cs
index ca34c80..a09b8ec 100644
--- a/CapMachine.Wpf/LinDrive/ToomossLin.cs
+++ b/CapMachine.Wpf/LinDrive/ToomossLin.cs
@@ -577,6 +577,8 @@ namespace CapMachine.Wpf.LinDrive
// 严重延迟,重新校准
NextExecutionTime = Stopwatcher.ElapsedTicks;
Console.WriteLine("定时发送延迟过大,重新校准时间");
+
+ LoggerService.Info("定时发送延迟过大,重新校准时间");
}
// 使用Stopwatch记录实际的执行间隔,而不是DateTime
@@ -585,7 +587,6 @@ namespace CapMachine.Wpf.LinDrive
//Console.WriteLine($"--当前时间(毫秒): {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}");
-
// 执行发送CAN逻辑
{
diff --git a/CapMachine.Wpf/MapperProfile/CANScheduleConfigProfile.cs b/CapMachine.Wpf/MapperProfile/CANScheduleConfigProfile.cs
new file mode 100644
index 0000000..b03cc2e
--- /dev/null
+++ b/CapMachine.Wpf/MapperProfile/CANScheduleConfigProfile.cs
@@ -0,0 +1,14 @@
+using AutoMapper;
+using CapMachine.Model.CANLIN;
+using CapMachine.Wpf.Dtos;
+
+namespace CapMachine.Wpf.MapperProfile
+{
+ public class CANScheduleConfigProfile : Profile
+ {
+ public CANScheduleConfigProfile()
+ {
+ CreateMap().ReverseMap();
+ }
+ }
+}
diff --git a/CapMachine.Wpf/Services/CanDriveService.cs b/CapMachine.Wpf/Services/CanDriveService.cs
index 8ad4863..762ecae 100644
--- a/CapMachine.Wpf/Services/CanDriveService.cs
+++ b/CapMachine.Wpf/Services/CanDriveService.cs
@@ -1,5 +1,6 @@
using CapMachine.Model.CANLIN;
using CapMachine.Wpf.CanDrive;
+using CapMachine.Wpf.Dtos;
using ImTools;
using Prism.Ioc;
using Prism.Mvvm;
@@ -126,6 +127,11 @@ namespace CapMachine.Wpf.Services
///
public List CmdData { get; set; } = new List();
+ ///
+ /// CNA 调度表的配置信息
+ ///
+ public List ListCANScheduleConfig { get; set; }
+
///
/// 增加发送的指令数据
///
@@ -307,10 +313,39 @@ namespace CapMachine.Wpf.Services
{
if (CmdData.Count > 0)
{
- ToomossCanDrive.IsCycleSend = true;
+
ToomossCanDrive.CmdData = CmdData;
- //ToomossCanDrive.StartCycleSendMsg();
- ToomossCanDrive.StartPrecisionCycleSendMsg();
+ ToomossCanDrive.SchEnable = true;
+
+ if (ToomossCanDrive.SchEnable)
+ {
+
+ //使用调度表的话,需要在调度表中配置信息后才可以进行操作
+ var GroupMsg = ToomossCanDrive.CmdData.GroupBy(a => a.MsgName).ToList();
+ foreach (var itemMsg in GroupMsg)
+ {
+ if (!ListCANScheduleConfig.ToList().Any(a => a.MsgName == itemMsg.Key))
+ {
+ System.Windows.MessageBox.Show($"你使能了调度表,但是调度表中没有设置【{itemMsg.Key}】信息,请设置后再操作", "提示", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Hand);
+ return;
+ }
+ }
+
+ if (ListCANScheduleConfig == null && ListCANScheduleConfig!.Count() == 0)
+ {
+ System.Windows.MessageBox.Show("调度表配置为空数据,请检查!将无法发送数据", "提示", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Hand);
+ return;
+ }
+ ToomossCanDrive.ListCANScheduleConfig = ListCANScheduleConfig!;
+ ToomossCanDrive.StartSchedule();
+ ToomossCanDrive.StartCycleUpdateCmd();
+ }
+ else
+ {
+ ToomossCanDrive.StartCycleSendMsg();
+ }
+
+ ToomossCanDrive.IsCycleSend = true;
}
else
{
@@ -319,7 +354,15 @@ namespace CapMachine.Wpf.Services
}
else
{
- ToomossCanDrive.IsCycleSend = false;
+ if (ToomossCanDrive.SchEnable)
+ {
+ ToomossCanDrive.IsCycleSend = false;
+ ToomossCanDrive.StopSchedule();
+ }
+ else
+ {
+ ToomossCanDrive.IsCycleSend = false;
+ }
}
}
@@ -388,7 +431,7 @@ namespace CapMachine.Wpf.Services
//double.TryParse(ListCanDbcModel.FindFirst(a => a.Name == Name).SignalRtValue, out double Result1);
//return double.TryParse(ListCanDbcModel.FindFirst(a => a.Name == Name).SignalRtValue.Split(" ")[0], out double Result) == true ? Result : 0;
return double.TryParse(ListCanDbcModel.FindFirst(a => a.Name == Name).SignalRtValue.Split(" ")[0], out double Result) == true ? Result : 0;
-
+
}
return 0;
}
diff --git a/CapMachine.Wpf/ViewModels/CANConfigViewModel.cs b/CapMachine.Wpf/ViewModels/CANConfigViewModel.cs
index c5c2516..d64097e 100644
--- a/CapMachine.Wpf/ViewModels/CANConfigViewModel.cs
+++ b/CapMachine.Wpf/ViewModels/CANConfigViewModel.cs
@@ -182,6 +182,7 @@ namespace CapMachine.Wpf.ViewModels
canLinConfigPros = FreeSql.Select().Where(a => a.CANLINInfo == CANLIN.CAN)
.Include(a => a.CANConfigExd)
.IncludeMany(a => a.CanLinConfigContents, then => then.Include(b => b.LogicRule))//,then=> then.Include(b=>b.LogicRule) //.IncludeMany(a => a.CanLinConfigContents)
+ .IncludeMany(a => a.CanScheduleConfigs)//
.ToList();
ListCanLinConfigPro = new ObservableCollection(canLinConfigPros);
@@ -225,6 +226,12 @@ namespace CapMachine.Wpf.ViewModels
{
ListReadCanLinRWConfigDto = new ObservableCollection(Mapper.Map>(ReadData));
}
+ //调度表配置信息
+ if (SelectCanLinConfigPro.CanScheduleConfigs != null && SelectCanLinConfigPro.CanScheduleConfigs.Count() > 0)
+ {
+ ListCANScheduleConfigDto = new ObservableCollection(Mapper.Map>(SelectCanLinConfigPro.CanScheduleConfigs));
+ }
+
//匹配选中的SelectCanLinConfigPro.CanLinConfigContents和ListCanDbcModel
MatchSeletedAndCanDbcModel();
@@ -584,6 +591,17 @@ namespace CapMachine.Wpf.ViewModels
SelectCanLinConfigProConfigName = SelectCanLinConfigPro.ConfigName;
+ //调度表配置信息
+ if (SelectCanLinConfigPro.CanScheduleConfigs != null && SelectCanLinConfigPro.CanScheduleConfigs.Count() > 0)
+ {
+ ListCANScheduleConfigDto = new ObservableCollection(Mapper.Map>(SelectCanLinConfigPro.CanScheduleConfigs));
+ }
+ else
+ {
+ ListCANScheduleConfigDto = new ObservableCollection();
+ }
+
+
return;
}
//先判断是否是正确的集合数据,防止DataGrid的数据源刷新导致的触发事件
@@ -868,7 +886,7 @@ namespace CapMachine.Wpf.ViewModels
private ObservableCollection _DataBaudRateCbxItems;
///
- /// CAN FD 数据波特率
+ /// CAN 数据波特率
///
public ObservableCollection DataBaudRateCbxItems
{
@@ -876,6 +894,47 @@ namespace CapMachine.Wpf.ViewModels
set { _DataBaudRateCbxItems = value; RaisePropertyChanged(); }
}
+ private DelegateCommand