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 c78cfd3..abc6c39 100644
--- a/CapMachine.Model/CANLIN/CanLinConfigPro.cs
+++ b/CapMachine.Model/CANLIN/CanLinConfigPro.cs
@@ -44,6 +44,17 @@ namespace CapMachine.Model.CANLIN
public List? CanLinConfigContents { get; set; }
+ ///
+ /// ///////////////////////////////////////////导航属性///////////////////////////////////////////////////////
+ ///
+ ///CAN 的调度表配置模式
+ public List? CanScheduleConfigs { get; set; }
+
+ ///
+ /// ///////////////////////////////////////////导航属性///////////////////////////////////////////////////////
+ ///
+ ///LIN 的调度表配置模式
+ public List? LinScheduleConfigs { get; set; }
///
/// ///////////////////////////////////////////导航属性 LIN 一对一///////////////////////////////////////////////////////
diff --git a/CapMachine.Model/CANLIN/LINScheduleConfig.cs b/CapMachine.Model/CANLIN/LINScheduleConfig.cs
new file mode 100644
index 0000000..496ea73
--- /dev/null
+++ b/CapMachine.Model/CANLIN/LINScheduleConfig.cs
@@ -0,0 +1,53 @@
+using FreeSql.DataAnnotations;
+
+namespace CapMachine.Model.CANLIN
+{
+ ///
+ /// 调度表的配置
+ /// 其实这些调度表是在DBC中有的,但是图莫斯的驱动没有读取到这些信息
+ /// 那么我们在系统层面进行操作和保存这些信息
+ ///
+ [Table(Name = "LINScheduleConfig")]
+ public class LINScheduleConfig
+ {
+ ///
+ /// 主键
+ ///
+ [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; }
+
+ ///
+ /// 调度表的Index
+ /// LDF中可能有多个调度器
+ ///
+ [Column(Name = "SchTabIndex")]
+ public int SchTabIndex { get; set; }
+
+ ///
+ /// 调度表的名称
+ /// LDF中可能有多个调度器名称
+ ///
+ [Column(Name = "SchTabName")]
+ public int SchTabName { get; set; }
+
+
+ ///
+ /// ///////////////////////////////////////////导航属性///////////////////////////////////////////////////////
+ ///
+
+ public long CanLinConfigProId { get; set; }
+ public CanLinConfigPro? CanLinConfigPro { get; set; }
+ }
+}
diff --git a/CapMachine.Wpf/App.xaml.cs b/CapMachine.Wpf/App.xaml.cs
index 89cbb16..7f555d9 100644
--- a/CapMachine.Wpf/App.xaml.cs
+++ b/CapMachine.Wpf/App.xaml.cs
@@ -209,6 +209,7 @@ namespace CapMachine.Wpf
containerRegistry.RegisterDialog();
containerRegistry.RegisterDialog();
containerRegistry.RegisterDialog();
+ containerRegistry.RegisterDialog();
containerRegistry.RegisterDialog();
diff --git a/CapMachine.Wpf/CanDrive/ToomossCan.cs b/CapMachine.Wpf/CanDrive/ToomossCan.cs
index 6c46427..565b5df 100644
--- a/CapMachine.Wpf/CanDrive/ToomossCan.cs
+++ b/CapMachine.Wpf/CanDrive/ToomossCan.cs
@@ -1,4 +1,5 @@
-using CapMachine.Wpf.Models.Tag;
+using CapMachine.Wpf.Dtos;
+using CapMachine.Wpf.Models.Tag;
using CapMachine.Wpf.Services;
using HslCommunication;
using ImTools;
@@ -37,6 +38,7 @@ namespace CapMachine.Wpf.CanDrive
ContainerProvider = containerProvider;
HighSpeedDataService = ContainerProvider.Resolve();
HightDriveMsgService = ContainerProvider.Resolve();
+ LoggerService = ContainerProvider.Resolve();
//Stopwatch.Frequency表示高精度计时器每秒的计数次数(ticks/秒)每毫秒的ticks数 = 每秒的ticks数 ÷ 1000
TicksPerMs = Stopwatch.Frequency / 1000.0;
@@ -67,6 +69,11 @@ namespace CapMachine.Wpf.CanDrive
///
public HightDriveMsgService HightDriveMsgService { get; set; }
+ ///
+ /// Logger 实例
+ ///
+ public ILogService LoggerService { get; set; }
+
///
/// 开始Dbc文件写入
///
@@ -485,6 +492,12 @@ namespace CapMachine.Wpf.CanDrive
}
}
+
+ ///
+ /// 定时扫描更新数据 扫描Task
+ ///
+ private static Task CycleUpdateCmdTask { get; set; }
+
///
/// 循环发送数据
///
@@ -759,6 +772,351 @@ 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 = 100;
+
+ ///
+ /// 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;
+
+ //设置当前这个报文的在调度表中的发送周期
+ SchCanMsg[Index].TimeStamp = (uint)ListCANScheduleConfig.FindFirst(a => a.MsgName == itemMsg.Key).Cycle;
+ }
+ Index++;
+ }
+ //通过DBC写入数据后生成CanMsg
+ //将信号值填入CAN消息里面
+ //释放申请的临时缓冲区
+ Marshal.FreeHGlobal(msgPtSend);
+
+ //********就是可以设置多个调度表放那里,但是运行时同一个时刻只能运行调度表其中的一个 ********
+ //****** 控制报文SchCanMsg和调度器中第一个调度器中的报文集合和要更新的报文集合都是同一个变量SchCanMsg, ********
+ // *** SchCanMsg的Index序号和ListCANScheduleConfig的MsgIndex是一样的 ***
+
+ //图莫斯的Sample:总共3个调度表,第一个表里面包含3帧数据,第二个调度表包含6帧数据,第三个调度表包含11帧数据
+ //预设5个调度表,但是我们只用其中第一个调度表,第一个调度表中包括多少消息帧,由系统的控制指令的帧的分布决定,SchCanMsg.Count()是所需要的控制发送的帧,都放到第一个调度表中
+
+ MsgTabNum = new Byte[MsgTabCount] { (byte)SchCanMsg.Count(), 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;
+ }
+
+ //约定使用Index=0 1号调度器,因为同一个时刻只能有一个调度器工作,把所有的报文都要放到这个调度器中
+ //CAN_MSG的TimeStamp就是这个报文发送的周期,由调度器协调
+ ret = USB2CAN.CAN_StartSchedule(DevHandle, WriteCANIndex, (byte)0, (byte)100, (byte)ListCANScheduleConfig.FirstOrDefault()!.OrderSend);
+ if (ret == USB2CAN.CAN_SUCCESS)
+ {
+ Console.WriteLine($"Start CAN Schedule 1 Success,SchTabIndex:{(byte)0} - Cycle:{(byte)100} - OrderSend:{(byte)1}");
+ }
+ else
+ {
+ Console.WriteLine("Start CAN Schedule 1 Error ret = {0}", ret);
+ LoggerService.Info($"Start CAN Schedule 1 Error;");
+ 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)
+ {
+ IsSendOk = false;
+ 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);
+
+ //CAN_UpdateSchedule 官网解释
+ // ---MsgTabIndex CAN调度表索引号
+ // ---MsgIndex 开始更新帧起始索引,若起始索引大于调度表帧数,则将帧添加到调度表后面
+ // ---pCanMsg 需要更新的CAN帧指针
+ // ---MsgNum pCanMsgTab里面包含的有效帧数
+
+ //CAN_UpdateSchedule中的MsgIndex表示当前的调度器中的帧Index序号
+ //因为调度表中的帧集合和控制帧的集合和要更新的帧集合都是同一个集合SchCanMsg
+ //默认1号调度表,一个更新所有的帧数据
+ var ret = USB2CAN.CAN_UpdateSchedule(DevHandle, WriteCANIndex, (byte)0, (byte)(0), SchCanMsg, (byte)SchCanMsg.Count());//配置调度表,该函数耗时可能会比较长,但是只需要执行一次即可
+ if (ret == USB2CAN.CAN_SUCCESS)
+ {
+ IsSendOk = true;
+ Console.WriteLine($"Update CAN Schedule Success -- SchTabIndex:{(byte)0} -- MsgIndex:{(byte)(0)} ");
+ }
+ else
+ {
+ IsSendOk = false;
+ Console.WriteLine($"Update CAN Schedule Error ret = {ret} -- SchTabIndex:{(byte)0} -- MsgIndex:{(byte)(0)}");
+ //return;
+ }
+
+ //一个报文帧一个报文帧进行更新数据
+ ////配置信息 默认启用1号调度器,MsgTabIndex=0;
+ //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)0, (byte)(itemMsgSchConfig.MsgIndex), 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)
+ {
+ IsSendOk = false;
+ LoggerService.Info($"时间:{DateTime.Now.ToString()}-【MSG】-{ex.Message}");
+ }
+ }
+
+ IsSendOk = false;
+ });
+ }
+
+
+ #endregion
+
+
///
/// 循环获取CAN消息
///
@@ -918,6 +1276,10 @@ namespace CapMachine.Wpf.CanDrive
DbcParserState = false;
IsCycleRevice = false;
IsCycleSend = false;
+ if (SchEnable)
+ {
+ StopSchedule();
+ }
}
}
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/Dtos/CANConfigExdDto.cs b/CapMachine.Wpf/Dtos/CANConfigExdDto.cs
index 7018cf1..40b75be 100644
--- a/CapMachine.Wpf/Dtos/CANConfigExdDto.cs
+++ b/CapMachine.Wpf/Dtos/CANConfigExdDto.cs
@@ -43,5 +43,17 @@ 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/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/Dtos/LINScheduleConfigDto.cs b/CapMachine.Wpf/Dtos/LINScheduleConfigDto.cs
new file mode 100644
index 0000000..380b7eb
--- /dev/null
+++ b/CapMachine.Wpf/Dtos/LINScheduleConfigDto.cs
@@ -0,0 +1,82 @@
+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
+{
+ public class LINScheduleConfigDto : 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 _SchTabIndex;
+ ///
+ /// 调度表的Index序列
+ ///
+ public int SchTabIndex
+ {
+ get { return _SchTabIndex; }
+ set { _SchTabIndex = value; RaisePropertyChanged(); }
+ }
+
+ private string? _SchTabName;
+ ///
+ /// 调度表的名称
+ ///
+ public string? SchTabName
+ {
+ get { return _SchTabName; }
+ set { _SchTabName = 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/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/MapperProfile/LINScheduleConfigProfile.cs b/CapMachine.Wpf/MapperProfile/LINScheduleConfigProfile.cs
new file mode 100644
index 0000000..7654552
--- /dev/null
+++ b/CapMachine.Wpf/MapperProfile/LINScheduleConfigProfile.cs
@@ -0,0 +1,14 @@
+using AutoMapper;
+using CapMachine.Model.CANLIN;
+using CapMachine.Wpf.Dtos;
+
+namespace CapMachine.Wpf.MapperProfile
+{
+ public class LINScheduleConfigProfile : Profile
+ {
+ public LINScheduleConfigProfile()
+ {
+ CreateMap().ReverseMap();
+ }
+ }
+}
diff --git a/CapMachine.Wpf/Services/CanDriveService.cs b/CapMachine.Wpf/Services/CanDriveService.cs
index 71ac18d..ec00ac4 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;
@@ -189,6 +190,12 @@ namespace CapMachine.Wpf.Services
///
public List CmdData { get; set; } = new List();
+
+ ///
+ /// CNA 调度表的配置信息
+ ///
+ public List ListCANScheduleConfig { get; set; }
+
///
/// 增加发送的指令数据
///
@@ -388,14 +395,43 @@ namespace CapMachine.Wpf.Services
{
if (ToomossCanDrive.OpenState)
{
- if (ToomossCanDrive.IsCycleSend == false)//要防止多次启动导致的问题,来回转换
+ if (ToomossCanDrive.IsCycleSend == false)
{
if (CmdData.Count > 0)
{
- ToomossCanDrive.IsCycleSend = true;
+
ToomossCanDrive.CmdData = CmdData;
- //ToomossCanDrive.StartCycleSendMsg();
- ToomossCanDrive.StartPrecisionCycleSendMsg();
+
+ 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.StartPrecisionCycleSendMsg();
+ //ToomossCanDrive.StartCycleSendMsg();
+ }
+
+ ToomossCanDrive.IsCycleSend = true;
}
else
{
@@ -404,7 +440,15 @@ namespace CapMachine.Wpf.Services
}
else
{
- ToomossCanDrive.IsCycleSend = false;
+ if (ToomossCanDrive.SchEnable)
+ {
+ ToomossCanDrive.IsCycleSend = false;
+ ToomossCanDrive.StopSchedule();
+ }
+ else
+ {
+ ToomossCanDrive.IsCycleSend = false;
+ }
}
}
diff --git a/CapMachine.Wpf/ViewModels/CANConfigViewModel.cs b/CapMachine.Wpf/ViewModels/CANConfigViewModel.cs
index 425dc84..e54aa2c 100644
--- a/CapMachine.Wpf/ViewModels/CANConfigViewModel.cs
+++ b/CapMachine.Wpf/ViewModels/CANConfigViewModel.cs
@@ -230,11 +230,27 @@ namespace CapMachine.Wpf.ViewModels
//});
}
}
+ else
+ {
+ ListWriteCanLinRWConfigDto = new ObservableCollection();
+ }
+
+
var ReadData = SelectCanLinConfigPro.CanLinConfigContents!.Where(a => a.RWInfo == RW.Read).ToList();
if (ReadData != null && ReadData.Count > 0)
{
ListReadCanLinRWConfigDto = new ObservableCollection(Mapper.Map>(ReadData));
}
+ else
+ {
+ ListReadCanLinRWConfigDto = new ObservableCollection();
+ }
+
+ //调度表配置信息
+ if (SelectCanLinConfigPro.CanScheduleConfigs != null && SelectCanLinConfigPro.CanScheduleConfigs.Count() > 0)
+ {
+ ListCANScheduleConfigDto = new ObservableCollection(Mapper.Map>(SelectCanLinConfigPro.CanScheduleConfigs));
+ }
//匹配选中的SelectCanLinConfigPro.CanLinConfigContents和ListCanDbcModel
MatchSeletedAndCanDbcModel();
@@ -586,14 +602,34 @@ namespace CapMachine.Wpf.ViewModels
}
}
+ else
+ {
+ ListWriteCanLinRWConfigDto = new ObservableCollection();
+ }
+
var ReadData = SelectCanLinConfigPro.CanLinConfigContents!.Where(a => a.RWInfo == RW.Read).ToList();
if (ReadData != null && ReadData.Count > 0)
{
ListReadCanLinRWConfigDto = new ObservableCollection(Mapper.Map>(ReadData));
}
+ else
+ {
+ ListReadCanLinRWConfigDto = new ObservableCollection();
+ }
SelectCanLinConfigProConfigName = SelectCanLinConfigPro.ConfigName;
+ //调度表配置信息
+ if (SelectCanLinConfigPro.CanScheduleConfigs != null && SelectCanLinConfigPro.CanScheduleConfigs.Count() > 0)
+ {
+ ListCANScheduleConfigDto = new ObservableCollection(Mapper.Map>(SelectCanLinConfigPro.CanScheduleConfigs));
+ }
+ else
+ {
+ ListCANScheduleConfigDto = new ObservableCollection();
+ }
+
+
return;
}
//先判断是否是正确的集合数据,防止DataGrid的数据源刷新导致的触发事件
@@ -876,6 +912,49 @@ namespace CapMachine.Wpf.ViewModels
set { _SelectedCANConfigExdDto = value; RaisePropertyChanged(); }
}
+
+ private DelegateCommand