From 88a6986f020d8050681f5575d1ac134612c1ceda Mon Sep 17 00:00:00 2001 From: Tyrone CT Date: Sat, 13 Sep 2025 15:43:05 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0CAN=20=E8=B0=83=E5=BA=A6?= =?UTF-8?q?=E8=A1=A8=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CapMachine.Model/CANLIN/CANConfigExd.cs | 5 + CapMachine.Model/CANLIN/CANScheduleConfig.cs | 55 +++ CapMachine.Model/CANLIN/CanLinConfigPro.cs | 11 + CapMachine.Model/CANLIN/LINScheduleConfig.cs | 53 +++ CapMachine.Wpf/App.xaml.cs | 1 + CapMachine.Wpf/CanDrive/ToomossCan.cs | 364 ++++++++++++++++- CapMachine.Wpf/CanDrive/usb2can.cs | 16 + CapMachine.Wpf/Dtos/CANConfigExdDto.cs | 12 + CapMachine.Wpf/Dtos/CANScheduleConfigDto.cs | 83 ++++ CapMachine.Wpf/Dtos/LINScheduleConfigDto.cs | 82 ++++ .../MapperProfile/CANScheduleConfigProfile.cs | 14 + .../MapperProfile/LINScheduleConfigProfile.cs | 14 + CapMachine.Wpf/Services/CanDriveService.cs | 54 ++- .../ViewModels/CANConfigViewModel.cs | 139 ++++++- .../ViewModels/DialogCANSchConfigViewModel.cs | 380 ++++++++++++++++++ .../ViewModels/LinConfigViewModel.cs | 7 + CapMachine.Wpf/Views/CANConfigView.xaml | 42 ++ .../Views/DialogCANSchConfigView.xaml | 206 ++++++++++ .../Views/DialogCANSchConfigView.xaml.cs | 28 ++ 19 files changed, 1559 insertions(+), 7 deletions(-) create mode 100644 CapMachine.Model/CANLIN/CANScheduleConfig.cs create mode 100644 CapMachine.Model/CANLIN/LINScheduleConfig.cs create mode 100644 CapMachine.Wpf/Dtos/CANScheduleConfigDto.cs create mode 100644 CapMachine.Wpf/Dtos/LINScheduleConfigDto.cs create mode 100644 CapMachine.Wpf/MapperProfile/CANScheduleConfigProfile.cs create mode 100644 CapMachine.Wpf/MapperProfile/LINScheduleConfigProfile.cs create mode 100644 CapMachine.Wpf/ViewModels/DialogCANSchConfigViewModel.cs create mode 100644 CapMachine.Wpf/Views/DialogCANSchConfigView.xaml create mode 100644 CapMachine.Wpf/Views/DialogCANSchConfigView.xaml.cs 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 _SchEnableCmd; + /// + /// 调度表的使能 操作的指令 + /// + public DelegateCommand SchEnableCmd + { + set + { + _SchEnableCmd = value; + } + get + { + if (_SchEnableCmd == null) + { + _SchEnableCmd = new DelegateCommand((Par) => SchEnableCmdCall(Par)); + } + return _SchEnableCmd; + } + } + + /// + /// 调度表的使能信息 + /// + /// + /// + private void SchEnableCmdCall(object par) + { + var dd = SelectedCANConfigExdDto.SchEnable; + var Result = (bool)par; + if (Result) + { + CanDriveService.ToomossCanDrive.SchEnable = true; + + } + else + { + CanDriveService.ToomossCanDrive.SchEnable = false; + + } + } + + private DelegateCommand _CanOpCmd; /// /// CAN操作的指令 @@ -1024,6 +1103,13 @@ namespace CapMachine.Wpf.ViewModels break; case "CycleSend"://循环发送你 + + //有可能加载完毕后不手动改变状态,导致值没有传输,所以这里赋值 + CanDriveService.ToomossCanDrive.SchEnable = SelectedCANConfigExdDto.SchEnable; + //无论有没有调度表,都要把这个配置给CanDriveService + CanDriveService.ListCANScheduleConfig = ListCANScheduleConfigDto.ToList(); + + //循环发送数据 CanDriveService.CycleSendMsg(); @@ -1074,7 +1160,7 @@ namespace CapMachine.Wpf.ViewModels //ToDo cmd CanDriveService.CanAutoHand = (bool)Data!; //CAN手自动切换时报文的展示需要配置一下,自动时报文不再展示(节省资源),手动时报文才展示, - HightDriveMsgService.IsDisplayEnabled= !(bool)Data!; + HightDriveMsgService.IsDisplayEnabled = !(bool)Data!; } } @@ -1189,6 +1275,19 @@ namespace CapMachine.Wpf.ViewModels set { _ReadRuleCbxItems = value; RaisePropertyChanged(); } } + + + private ObservableCollection _ListCANScheduleConfigDto; + /// + ///调度表集合 + /// + public ObservableCollection ListCANScheduleConfigDto + { + get { return _ListCANScheduleConfigDto; } + set { _ListCANScheduleConfigDto = value; RaisePropertyChanged(); } + } + + //private string _SelectedWriteName; ///// ///// 选中的写入的Name @@ -1338,6 +1437,44 @@ namespace CapMachine.Wpf.ViewModels System.Windows.MessageBox.Show("请选中后再进行【删除】操作?", "提示", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Hand); } + break; + case "WriteSch"://调度表 + + var data = CanDriveService.CmdData.GroupBy(a => a.MsgName).Select(a => a.Key).ToList(); + + if (data != null && data.Count > 0) + { + //弹窗 + DialogService.ShowDialog("DialogCANSchConfigView", new DialogParameters() { + {"ListMsg", CanDriveService.CmdData.GroupBy(a=>a.MsgName).Select(a=>a.Key).ToList() }, + { "ListCANScheduleConfigDto",ListCANScheduleConfigDto}, + { "SelectCanLinConfigProId",SelectCanLinConfigPro.Id}, + + }, (par) => + { + if (par.Result == ButtonResult.OK) + { + ////程序名称 + ListCANScheduleConfigDto = par.Parameters.GetValue>("ReturnValue"); + //把更新后的最新值给当前的主集合中 + SelectCanLinConfigPro.CanScheduleConfigs = Mapper.Map>(ListCANScheduleConfigDto.ToList()); + + } + else if (par.Result == ButtonResult.Cancel) + { + //取消 + + } + + }); + } + else + { + System.Windows.MessageBox.Show("未发现写入的执行的命令数据,无法配置?", "提示", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Hand); + } + + + break; default: break; diff --git a/CapMachine.Wpf/ViewModels/DialogCANSchConfigViewModel.cs b/CapMachine.Wpf/ViewModels/DialogCANSchConfigViewModel.cs new file mode 100644 index 0000000..9313f21 --- /dev/null +++ b/CapMachine.Wpf/ViewModels/DialogCANSchConfigViewModel.cs @@ -0,0 +1,380 @@ +using AutoMapper; +using CapMachine.Core; +using CapMachine.Model; +using CapMachine.Model.CANLIN; +using CapMachine.Wpf.Dtos; +using CapMachine.Wpf.Services; +using ImTools; +using Prism.Commands; +using Prism.Services.Dialogs; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace CapMachine.Wpf.ViewModels +{ + /// + /// CAN 调度表配置 + /// + public class DialogCANSchConfigViewModel : DialogViewModel + { + /// + /// 构造函数 + /// + public DialogCANSchConfigViewModel(IFreeSql freeSql, IMapper mapper) + { + Title = "调度表 CAN 配置"; + FreeSql = freeSql; + Mapper = mapper; + + + SendOrderCbxItems = new ObservableCollection() + { + new CbxItems(){ + Key="0", + Text="并行", + }, + new CbxItems(){ + Key="1", + Text="顺序", + }, + }; + + + //默认只能用1号调度器 + SchTabIndexCbxItems = new ObservableCollection() + { + new CbxItems(){ + Key="0", + Text="0", + }, + //new CbxItems(){ + // Key="1", + // Text="1", + //}, + //new CbxItems(){ + // Key="2", + // Text="2", + //}, + //new CbxItems(){ + // Key="3", + // Text="3", + //}, + //new CbxItems(){ + // Key="4", + // Text="4", + //}, + }; + + } + + public IFreeSql FreeSql { get; } + public IMapper Mapper { get; } + + private string name; + /// + /// 名称 + /// + public string Name + { + get { return name; } + set { name = value; RaisePropertyChanged(); } + } + + private ObservableCollection _ListCANScheduleConfigDto = new ObservableCollection(); + /// + /// CAN 调度表数据集合 + /// + public ObservableCollection ListCANScheduleConfigDto + { + get { return _ListCANScheduleConfigDto; } + set { _ListCANScheduleConfigDto = value; RaisePropertyChanged(); } + } + + /// + /// 消息/帧报文信息集合 + /// + public List ListMsg { get; set; } + + private ObservableCollection _MsgCbxItems; + /// + /// 消息名称 集合信息 + /// + public ObservableCollection MsgCbxItems + { + get { return _MsgCbxItems; } + set { _MsgCbxItems = value; RaisePropertyChanged(); } + } + + /// + /// 选中的程序的Id + /// + public long SelectCanLinConfigProId { get; set; } + + private ObservableCollection _SendOrderCbxItems; + /// + /// 发送方式 集合信息 + /// + public ObservableCollection SendOrderCbxItems + { + get { return _SendOrderCbxItems; } + set { _SendOrderCbxItems = value; RaisePropertyChanged(); } + } + + + private string? _CurSendOrder; + /// + /// 当前发送方式 + /// + public string? CurSendOrder + { + get { return _CurSendOrder; } + set { _CurSendOrder = value; RaisePropertyChanged(); } + } + + + private ObservableCollection _SchTabIndexCbxItems; + /// + /// 调度器序号 集合信息 + /// + public ObservableCollection SchTabIndexCbxItems + { + get { return _SchTabIndexCbxItems; } + set { _SchTabIndexCbxItems = value; RaisePropertyChanged(); } + } + + private CANScheduleConfigDto _CurSelectedItem; + /// + /// 选中的数据 + /// + public CANScheduleConfigDto CurSelectedItem + { + get { return _CurSelectedItem; } + set { _CurSelectedItem = value; RaisePropertyChanged(); } + } + + + private DelegateCommand _GridSelectionChangedCmd; + /// + /// 选中行数据命令 + /// + public DelegateCommand GridSelectionChangedCmd + { + set + { + _GridSelectionChangedCmd = value; + } + get + { + if (_GridSelectionChangedCmd == null) + { + _GridSelectionChangedCmd = new DelegateCommand((par) => GridSelectionChangedCmdMethod(par)); + } + return _GridSelectionChangedCmd; + } + } + private void GridSelectionChangedCmdMethod(object par) + { + //先判断是否是正确的集合数据,防止DataGrid的数据源刷新导致的触发事件 + var Selecteddata = par as CANScheduleConfigDto; + + if (Selecteddata != null) + { + CurSelectedItem = Selecteddata; + } + } + + //OpCmd + private DelegateCommand _OpCmd; + /// + /// 增加方法命令 + /// + public DelegateCommand OpCmd + { + set + { + _OpCmd = value; + } + get + { + if (_OpCmd == null) + { + _OpCmd = new DelegateCommand((Par) => OpCmdCall(Par)); + } + return _OpCmd; + } + } + + private void OpCmdCall(string Par) + { + switch (Par) + { + case "Add": + ListCANScheduleConfigDto.Add(new CANScheduleConfigDto + { + CanLinConfigProId = SelectCanLinConfigProId, + Cycle = 100, + SchTabIndex = 0, + OrderSend = 1, + }); + break; + case "Delete": + if (CurSelectedItem != null) + { + //直接删除掉,如果没有ID的话,这就不需要删除了 + FreeSql.Delete(CurSelectedItem.Id).ExecuteAffrows(); + ListCANScheduleConfigDto.Remove(CurSelectedItem); + + CurSelectedItem = null; + } + else + { + MessageBox.Show("请选中后再进行【删除】操作?", "提示", MessageBoxButton.OK, MessageBoxImage.Hand); + } + break; + default: + break; + } + } + + private DelegateCommand saveCmd; + /// + /// 保存命令 + /// + public DelegateCommand SaveCmd + { + set + { + saveCmd = value; + } + get + { + if (saveCmd == null) + { + saveCmd = new DelegateCommand(() => SaveCmdMethod()); + } + return saveCmd; + } + } + + /// + /// 保存命令方法 + /// + /// + private void SaveCmdMethod() + { + //检查空的数据 + foreach (var item in ListCANScheduleConfigDto) + { + //整个的发送方式赋值给每个子项 + item.OrderSend = CurSendOrder == "0" ? 0 : 1; + + if (string.IsNullOrEmpty(item.MsgName)) + { + MessageBox.Show("请确认消息名称是否正确", "提示", MessageBoxButton.OK, MessageBoxImage.Hand); + return; + } + if (item.Cycle == 0) + { + MessageBox.Show("请确认周期是否正确", "提示", MessageBoxButton.OK, MessageBoxImage.Hand); + return; + } + if (item.OrderSend >= 2) + { + MessageBox.Show("请确认发送方式是否正确", "提示", MessageBoxButton.OK, MessageBoxImage.Hand); + return; + } + } + + + //发送的控制帧都放到同一个调度表中,不需要检查了 + ////检查重复设置问题 + //bool isRepeat = ListCANScheduleConfigDto.GroupBy(i => i.MsgName).Any(g => g.Count() > 1); + //if (isRepeat) + //{ + // MessageBox.Show("请确认是否重复设置", "提示", MessageBoxButton.OK, MessageBoxImage.Hand); + // return; + //} + + //检查数据是否正常 + foreach (var item in ListCANScheduleConfigDto) + { + FreeSql.InsertOrUpdate() + .SetSource(Mapper.Map(item)). + ExecuteAffrows(); + } + + ListCANScheduleConfigDto = new ObservableCollection(Mapper.Map>(FreeSql.Select().Where(a => a.CanLinConfigProId == SelectCanLinConfigProId).ToList())); + + DialogParameters pars = new DialogParameters + { + { "ReturnValue", ListCANScheduleConfigDto } + }; + + RaiseRequestClose(new DialogResult(ButtonResult.OK, pars)); + } + + private DelegateCommand cancelCmd; + /// + /// 保存命令 + /// + public DelegateCommand CancelCmd + { + set + { + cancelCmd = value; + } + get + { + if (cancelCmd == null) + { + cancelCmd = new DelegateCommand(() => CancelCmdMethod()); + } + return cancelCmd; + } + } + + + /// + /// 取消命令方法 + /// + /// + private void CancelCmdMethod() + { + RaiseRequestClose(new DialogResult(ButtonResult.Cancel)); + } + + /// + /// 窗口打开时的传递的参数 + /// + /// + public override void OnDialogOpened(IDialogParameters parameters) + { + ListMsg = parameters.GetValue>("ListMsg"); + // 转换为CbxItems集合,都是文本内容 + MsgCbxItems = new ObservableCollection( + ListMsg.Select(value => new CbxItems + { + Key = value, + Text = value + })); + + ListCANScheduleConfigDto = parameters.GetValue>("ListCANScheduleConfigDto"); + //防止返回的数据为空,就无法增加了 + if (ListCANScheduleConfigDto == null) ListCANScheduleConfigDto = new ObservableCollection(); + //Name = parameters.GetValue("Name"); + if (ListCANScheduleConfigDto.Count > 0) + { + CurSendOrder = ListCANScheduleConfigDto.FirstOrDefault()!.OrderSend.ToString(); + } + + SelectCanLinConfigProId = parameters.GetValue("SelectCanLinConfigProId"); + } + + + } +} diff --git a/CapMachine.Wpf/ViewModels/LinConfigViewModel.cs b/CapMachine.Wpf/ViewModels/LinConfigViewModel.cs index 3f3110e..7ff386a 100644 --- a/CapMachine.Wpf/ViewModels/LinConfigViewModel.cs +++ b/CapMachine.Wpf/ViewModels/LinConfigViewModel.cs @@ -84,6 +84,13 @@ namespace CapMachine.Wpf.ViewModels new CbxItems(){ Key="通讯功率",Text="通讯功率"}, new CbxItems(){ Key="通讯逆变器温度",Text="通讯逆变器温度"}, new CbxItems(){ Key="通讯芯片温度",Text="通讯芯片温度"}, + + new CbxItems(){ Key="通讯PTC入水温度",Text="通讯PTC入水温度"}, + new CbxItems(){ Key="通讯PTC出水温度",Text="通讯PTC出水温度"}, + new CbxItems(){ Key="通讯PTC峰值电流",Text="通讯PTC峰值电流"}, + new CbxItems(){ Key="通讯PTC母线电流",Text="通讯PTC母线电流"}, + new CbxItems(){ Key="通讯PTC膜温",Text="通讯PTC膜温"}, + new CbxItems(){ Key="通讯PTC模块温度",Text="通讯PTC模块温度"}, }; InitLoadLinConfigPro(); diff --git a/CapMachine.Wpf/Views/CANConfigView.xaml b/CapMachine.Wpf/Views/CANConfigView.xaml index 686ad78..b946d19 100644 --- a/CapMachine.Wpf/Views/CANConfigView.xaml +++ b/CapMachine.Wpf/Views/CANConfigView.xaml @@ -671,8 +671,32 @@ + + + + + + @@ -731,6 +755,24 @@ Margin="0,0,15,0" HorizontalAlignment="Right" Orientation="Horizontal"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +