From 2c0575eea73e70ff6ed777399a5d0964678023bf Mon Sep 17 00:00:00 2001 From: Tyrone CT Date: Mon, 8 Sep 2025 23:04:48 +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=E7=9A=84=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 | 18 +- CapMachine.Model/CANLIN/LINScheduleConfig.cs | 53 +++ CapMachine.Wpf/CanDrive/ToomossCan.cs | 415 +++++++++++++++++- CapMachine.Wpf/CanDrive/usb2can.cs | 16 + CapMachine.Wpf/Dtos/CANConfigExdDto.cs | 12 +- CapMachine.Wpf/Dtos/CANScheduleConfigDto.cs | 83 ++++ .../MapperProfile/CANScheduleConfigProfile.cs | 14 + CapMachine.Wpf/Services/CanDriveService.cs | 78 +++- .../ViewModels/CANConfigViewModel.cs | 241 +++++++++- CapMachine.Wpf/Views/CANConfigView.xaml | 123 +++++- 12 files changed, 1086 insertions(+), 27 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/MapperProfile/CANScheduleConfigProfile.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 d754453..48f1f48 100644 --- a/CapMachine.Model/CANLIN/CanLinConfigPro.cs +++ b/CapMachine.Model/CANLIN/CanLinConfigPro.cs @@ -44,12 +44,26 @@ namespace CapMachine.Model.CANLIN public List? CanLinConfigContents { get; set; } + /// + /// ///////////////////////////////////////////导航属性/////////////////////////////////////////////////////// + /// + ///CAN 的调度表配置模式 + public List? CanScheduleConfigs { get; set; } + + /// + /// ///////////////////////////////////////////导航属性/////////////////////////////////////////////////////// + /// + ///LIN 的调度表配置模式 + public List? LinScheduleConfigs { get; set; } + + /// /// ///////////////////////////////////////////导航属性 LIN 一对一/////////////////////////////////////////////////////// /// public long CANFdConfigExdId { get; set; } // 外键字段,必要 public CANFdConfigExd CANFdConfigExd { get; set; } + /// /// ///////////////////////////////////////////导航属性 CAN 一对一/////////////////////////////////////////////////////// /// @@ -57,12 +71,12 @@ namespace CapMachine.Model.CANLIN public CANConfigExd CANConfigExd { get; set; } - - /// /// ///////////////////////////////////////////导航属性 LIN 一对一/////////////////////////////////////////////////////// /// public long LINConfigExdId { get; set; } // 外键字段,必要 public LINConfigExd LINConfigExd { get; set; } + + } } 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/CanDrive/ToomossCan.cs b/CapMachine.Wpf/CanDrive/ToomossCan.cs index e4c8dbe..82ce026 100644 --- a/CapMachine.Wpf/CanDrive/ToomossCan.cs +++ b/CapMachine.Wpf/CanDrive/ToomossCan.cs @@ -1,6 +1,11 @@ -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; using Prism.Mvvm; @@ -33,6 +38,7 @@ namespace CapMachine.Wpf.CanDrive { ContainerProvider = containerProvider; HighSpeedDataService = ContainerProvider.Resolve(); + LoggerService = ContainerProvider.Resolve(); //Stopwatch.Frequency表示高精度计时器每秒的计数次数(ticks/秒)每毫秒的ticks数 = 每秒的ticks数 ÷ 1000 TicksPerMs = Stopwatch.Frequency / 1000.0; @@ -57,6 +63,11 @@ namespace CapMachine.Wpf.CanDrive /// public HighSpeedDataService HighSpeedDataService { get; set; } + /// + /// Logger 实例 + /// + public ILogService LoggerService { get; set; } + /// /// 开始Dbc文件写入 /// @@ -123,6 +134,7 @@ namespace CapMachine.Wpf.CanDrive ///BufferSize 存储CAN消息缓冲区大小。 ///返回值: //大于等于0表示从CAN适配器内部成功读取到的CAN消息帧数,若返回值小于0则说明调用该函数失败。 + /// 目前是WriteCANIndex和ReadCANIndex需要相同 /// public Byte WriteCANIndex { get; set; } = 0; @@ -480,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; /// @@ -497,6 +514,24 @@ namespace CapMachine.Wpf.CanDrive RaisePropertyChanged(); _IsSendOk = value; } + //RaisePropertyChanged(); + } + } + + private bool _IsReviceOk; + /// + /// 接收报文是否OK + /// + public bool IsReviceOk + { + get { return _IsReviceOk; } + set + { + if (_IsReviceOk != value) + { + RaisePropertyChanged(); + _IsReviceOk = value; + } } } @@ -652,6 +687,7 @@ namespace CapMachine.Wpf.CanDrive // 严重延迟,重新校准 NextExecutionTime = Stopwatcher.ElapsedTicks; Console.WriteLine("定时发送延迟过大,重新校准时间"); + LoggerService.Info($"定时发送延迟过大,重新校准时间"); } // 使用Stopwatch记录实际的执行间隔,而不是DateTime @@ -710,32 +746,43 @@ namespace CapMachine.Wpf.CanDrive } catch (TaskCanceledException) { + LoggerService.Info($"精确周期发送CAN数据-任务被取消,正常退出"); // 任务被取消,正常退出 + IsSendOk = false; break; } catch (Exception ex) { Console.WriteLine($"CAN周期发送异常: {ex.Message}"); // 短暂暂停避免异常情况下CPU占用过高 + IsSendOk = false; await Task.Delay(10, token); + + LoggerService.Info($"精确周期发送CAN数据-{ex.Message}"); } } + + IsSendOk = false; } catch (Exception ex) { // 确保在任何情况下(正常退出、异常、取消)都会停止计时器 Stopwatcher.Stop(); - + LoggerService.Info($"精确周期发送CAN数据-{ex.Message}"); // 清理其他可能的资源 Console.WriteLine("CAN周期发送任务已结束,资源已清理"); + IsSendOk = false; } finally { // 确保在任何情况下(正常退出、异常、取消)都会停止计时器 Stopwatcher.Stop(); + LoggerService.Info("精确周期发送CAN数据-正常退出、异常、取消)都会停止计时器"); + IsSendOk = false; } }, token, TaskCreationOptions.LongRunning, TaskScheduler.Default); + } @@ -750,6 +797,348 @@ 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消息 @@ -764,12 +1153,14 @@ namespace CapMachine.Wpf.CanDrive try { //另外一个CAN通道读取数据 - USB2CAN.CAN_MSG[] CanMsgBuffer = new USB2CAN.CAN_MSG[128]; + USB2CAN.CAN_MSG[] CanMsgBuffer = new USB2CAN.CAN_MSG[1024]; //申请数据缓冲区 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, 1, msgPtRead, CanMsgBuffer.Length);//测试用,CAN卡 CAN1和CAN2 短接时测试用 if (CanNum > 0) { + IsReviceOk = true; Console.WriteLine("Read CanMsgNum = {0}", CanNum); for (int i = 0; i < CanNum; i++) { @@ -797,13 +1188,15 @@ namespace CapMachine.Wpf.CanDrive } else if (CanNum == 0) { + IsReviceOk = false; Console.WriteLine("No CAN data!"); } else { + IsReviceOk = false; Console.WriteLine("Get CAN data error!"); } - Console.WriteLine(""); + //Console.WriteLine(""); //将CAN消息数据填充到信号里面,用DBC解析数据 CAN_DBCParser.DBC_SyncCANMsgToValue(DBCHandle, msgPtRead, CanNum); @@ -838,9 +1231,15 @@ namespace CapMachine.Wpf.CanDrive } catch (Exception ex) { - //LogService.Info($"时间:{DateTime.Now.ToString()}-【Meter】-{ex.Message}"); + IsReviceOk = false; + LoggerService.Info("接收出现异常"); } + //finally + //{ + // IsReviceOk = false; + //} } + IsReviceOk = false; }); } @@ -903,6 +1302,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..665acbe 100644 --- a/CapMachine.Wpf/Dtos/CANConfigExdDto.cs +++ b/CapMachine.Wpf/Dtos/CANConfigExdDto.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; namespace CapMachine.Wpf.Dtos { - public class CANConfigExdDto:BindableBase + public class CANConfigExdDto : BindableBase { /// /// 主键 @@ -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/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/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 6c4648d..ded2774 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; @@ -20,15 +21,17 @@ namespace CapMachine.Wpf.Services { public HighSpeedDataService HighSpeedDataService { get; } + public LogicRuleService LogicRuleService { get; } /// /// 实例化函数 /// - public CanDriveService(HighSpeedDataService highSpeedDataService, IContainerProvider containerProvider) + public CanDriveService(HighSpeedDataService highSpeedDataService, IContainerProvider containerProvider, LogicRuleService logicRuleService) { ToomossCanDrive = new ToomossCan(containerProvider); //高速数据服务 HighSpeedDataService = highSpeedDataService; + LogicRuleService = logicRuleService; //ToomossCanDrive.StartCanDrive(); } @@ -124,6 +127,11 @@ namespace CapMachine.Wpf.Services /// public List CmdData { get; set; } = new List(); + /// + /// CNA 调度表的配置信息 + /// + public List ListCANScheduleConfig { get; set; } + /// /// 增加发送的指令数据 /// @@ -172,14 +180,26 @@ namespace CapMachine.Wpf.Services /// public void UpdateSpeedCmdData(double SpeedData) { + //if (SpeedCanCmdData != null) + //{ + // SpeedCanCmdData.SignalCmdValue = SpeedData; + //} if (SpeedCanCmdData != null) { - SpeedCanCmdData.SignalCmdValue = SpeedData; + //首先是否判断是有斜率 + if (SpeedCanCmdData.LogicRuleDto == null) + { + //没有启动逻辑规则处理 + SpeedCanCmdData.SignalCmdValue = SpeedData; + } + else + { + //LogicRuleService.ApplyExpressionFast(SpeedData, SpeedCanCmdData.LogicRuleDto); + SpeedCanCmdData.SignalCmdValue = LogicRuleService.ApplyExpressionFast(SpeedData, SpeedCanCmdData.LogicRuleDto); + //Console.WriteLine($"实时转换后转速值:{SpeedCanCmdData.SignalCmdValue}-SV值:{SpeedData}"); + } + } - //if (EnableCanCmdData != null) - //{ - // EnableCanCmdData.SignalCmdValue = 1; - //} } /// @@ -293,10 +313,39 @@ namespace CapMachine.Wpf.Services { 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 { @@ -305,7 +354,15 @@ namespace CapMachine.Wpf.Services } else { - ToomossCanDrive.IsCycleSend = false; + if (ToomossCanDrive.SchEnable) + { + ToomossCanDrive.IsCycleSend = false; + ToomossCanDrive.StopSchedule(); + } + else + { + ToomossCanDrive.IsCycleSend = false; + } } } @@ -374,6 +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 e877d89..d32eca0 100644 --- a/CapMachine.Wpf/ViewModels/CANConfigViewModel.cs +++ b/CapMachine.Wpf/ViewModels/CANConfigViewModel.cs @@ -37,7 +37,7 @@ namespace CapMachine.Wpf.ViewModels { public CANConfigViewModel(IDialogService dialogService, IFreeSql freeSql, IEventAggregator eventAggregator, IRegionManager regionManager, SysRunService sysRunService, - ComActionService actionService, + ComActionService actionService, LogicRuleService logicRuleService, ConfigService configService, CanDriveService canDriveService, IMapper mapper, MachineRtDataService machineRtDataService) { @@ -47,6 +47,7 @@ namespace CapMachine.Wpf.ViewModels RegionManager = regionManager; SysRunService = sysRunService; ComActionService = actionService; + LogicRuleService = logicRuleService; ConfigService = configService; CanDriveService = canDriveService; Mapper = mapper; @@ -55,6 +56,31 @@ namespace CapMachine.Wpf.ViewModels //MachineDataService = machineDataService; DialogService = dialogService; + EventAggregator.GetEvent().Subscribe(LogicRuleChangeEventCall); + + //数据波特率 + DataBaudRateCbxItems = new ObservableCollection() + { + new CbxItems(){ Key="100000",Text="100 Kbps"}, + new CbxItems(){ Key="125000",Text="125 Kbps"}, + new CbxItems(){ Key="200000",Text="200 Kbps"}, + new CbxItems(){ Key="250000",Text="250 Kbps"}, + new CbxItems(){ Key="400000",Text="400 Kbps"}, + new CbxItems(){ Key="500000",Text="500 Kbps"}, + new CbxItems(){ Key="666000",Text="666 Kbps"}, + new CbxItems(){ Key="800000",Text="800 Kbps"}, + new CbxItems(){ Key="1000000",Text="1.0 Mbps"}, + + new CbxItems(){ Key="1500000",Text="1.5 Mbps"}, + new CbxItems(){ Key="2000000",Text="2.0 Mbps"}, + new CbxItems(){ Key="3000000",Text="3.0 Mbps"}, + new CbxItems(){ Key="4000000",Text="4.0 Mbps"}, + new CbxItems(){ Key="5000000",Text="5.0 Mbps"}, + new CbxItems(){ Key="6700000",Text="6.7 Mbps"}, + new CbxItems(){ Key="8000000",Text="8.0 Mbps"}, + new CbxItems(){ Key="10000000",Text="10.0 Mbps"}, + }; + WriteNameCbxItems = new ObservableCollection() { new CbxItems(){ Key="转速",Text="转速"}, @@ -73,6 +99,7 @@ namespace CapMachine.Wpf.ViewModels new CbxItems(){ Key="通讯Cmp转速",Text="通讯Cmp转速"}, new CbxItems(){ Key="通讯Cmp母线电压",Text="通讯Cmp母线电压"}, new CbxItems(){ Key="通讯Cmp母线电流",Text="通讯Cmp母线电流"}, + new CbxItems(){ Key="通讯Cmp逆变器温度",Text="通讯Cmp逆变器温度"}, new CbxItems(){ Key="通讯Cmp相电流",Text="通讯Cmp相电流"}, new CbxItems(){ Key="通讯Cmp功率",Text="通讯Cmp功率"}, new CbxItems(){ Key="通讯Cmp芯片温度",Text="通讯Cmp芯片温度"}, @@ -85,7 +112,8 @@ namespace CapMachine.Wpf.ViewModels new CbxItems(){ Key="通讯PTC模块温度",Text="通讯PTC模块温度"}, }; InitLoadCanConfigPro(); - + //初始化写规则下拉框 + InitWriteRuleCbx(); } @@ -94,6 +122,7 @@ namespace CapMachine.Wpf.ViewModels /// public IFreeSql FreeSql { get; } public IEventAggregator EventAggregator { get; } + public LogicRuleService LogicRuleService { get; } public IRegionManager RegionManager { get; } public SysRunService SysRunService { get; } public ComActionService ComActionService { get; } @@ -108,6 +137,39 @@ namespace CapMachine.Wpf.ViewModels public IDialogService DialogService { get; } + #region 规则 + + + /// + /// 逻辑更改事件 + /// + /// + /// + private void LogicRuleChangeEventCall(string msg) + { + //InitWriteRuleCbx(); + } + + /// + /// 初始化写规则下拉框 + /// + private void InitWriteRuleCbx() + { + WriteRuleCbxItems = new ObservableCollection(); + //选择的读写规则 + foreach (var itemRule in LogicRuleService.LogicRuleDtos) + { + WriteRuleCbxItems.Add(new CbxItems() + { + Key = itemRule.Id.ToString(), + Text = itemRule.Name + }); + } + } + + + #endregion + #region CanConfigPro @@ -119,7 +181,8 @@ namespace CapMachine.Wpf.ViewModels //CAN配置集合数据 canLinConfigPros = FreeSql.Select().Where(a => a.CANLINInfo == CANLIN.CAN) .Include(a => a.CANConfigExd) - .IncludeMany(a => a.CanLinConfigContents) + .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); @@ -128,7 +191,7 @@ namespace CapMachine.Wpf.ViewModels SelectCanLinConfigPro = canLinConfigPros.Where(a => a.Id == SelectCanLinConfigPro.Id).FirstOrDefault()!; //无数据就返回 if (SelectCanLinConfigPro == null) return; - + SelectedCANConfigExdDto = Mapper.Map(SelectCanLinConfigPro!.CANConfigExd); //配置信息 @@ -147,6 +210,7 @@ namespace CapMachine.Wpf.ViewModels MsgName = item.MsgFrameName, SignalName = item.SignalName, SignalCmdValue = double.TryParse(item.DefautValue, out double result) == true ? result : 0, + LogicRuleDto = Mapper.Map(item.LogicRule), }); //CanDriveService.CmdData.Add(new CanCmdData() //{ @@ -157,11 +221,26 @@ 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(); @@ -500,6 +579,7 @@ namespace CapMachine.Wpf.ViewModels MsgName = item.MsgFrameName, SignalName = item.SignalName, SignalCmdValue = double.TryParse(item.DefautValue, out double result) == true ? result : 0, + LogicRuleDto = Mapper.Map(item.LogicRule), }); //CanDriveService.CmdData.Add(new CanCmdData() @@ -512,14 +592,33 @@ 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的数据源刷新导致的触发事件 @@ -707,7 +806,7 @@ namespace CapMachine.Wpf.ViewModels } //(par as SelectionChangedEventArgs)!.AddedItems[0] == null - if ((par as SelectionChangedEventArgs)!.AddedItems.Count==0) + if ((par as SelectionChangedEventArgs)!.AddedItems.Count == 0) { return; } @@ -802,6 +901,57 @@ namespace CapMachine.Wpf.ViewModels set { _SelectedCANConfigExdDto = value; RaisePropertyChanged(); } } + private ObservableCollection _DataBaudRateCbxItems; + /// + /// CAN 数据波特率 + /// + public ObservableCollection DataBaudRateCbxItems + { + get { return _DataBaudRateCbxItems; } + set { _DataBaudRateCbxItems = 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操作的指令 @@ -845,7 +995,7 @@ namespace CapMachine.Wpf.ViewModels //系统使用了CAN ConfigService.CanLinRunStateModel.CurSysSelectedCanLin = CanLinEnum.Can; } - + //CAN DBC配置 有DBC配置的话,则直接加载DBC信息 if (!string.IsNullOrEmpty(SelectCanLinConfigPro.CANConfigExd.DbcPath)) { @@ -889,6 +1039,7 @@ namespace CapMachine.Wpf.ViewModels .Set(a => a.DbcPath, SelectedCANConfigExdDto.DbcPath) .Set(a => a.Cycle, SelectedCANConfigExdDto.Cycle) .Set(a => a.BaudRate, SelectedCANConfigExdDto.BaudRate) + .Set(a => a.SchEnable, SelectedCANConfigExdDto.SchEnable) .Where(a => a.Id == SelectedCANConfigExdDto.Id) .ExecuteUpdated(); } @@ -950,7 +1101,12 @@ namespace CapMachine.Wpf.ViewModels break; case "CycleSend"://循环发送你 - //循环发送数据 + + //有可能加载完毕后不手动改变状态,导致值没有传输,所以这里赋值 + CanDriveService.ToomossCanDrive.SchEnable = SelectedCANConfigExdDto.SchEnable; + //无论有没有调度表,都要把这个配置给CanDriveService + CanDriveService.ListCANScheduleConfig = ListCANScheduleConfigDto.ToList(); + CanDriveService.CycleSendMsg(); //Listen @@ -992,6 +1148,16 @@ namespace CapMachine.Wpf.ViewModels set { _WriteNameCbxItems = value; RaisePropertyChanged(); } } + private ObservableCollection _WriteRuleCbxItems; + /// + /// 写入的规格集合 + /// + public ObservableCollection WriteRuleCbxItems + { + get { return _WriteRuleCbxItems; } + set { _WriteRuleCbxItems = value; RaisePropertyChanged(); } + } + private ObservableCollection _ReadNameCbxItems; /// @@ -1004,6 +1170,28 @@ namespace CapMachine.Wpf.ViewModels } + private ObservableCollection _ReadRuleCbxItems; + /// + /// 读取的规格集合 + /// + public ObservableCollection ReadRuleCbxItems + { + get { return _ReadRuleCbxItems; } + set { _ReadRuleCbxItems = value; RaisePropertyChanged(); } + } + + + private ObservableCollection _ListCANScheduleConfigDto; + /// + ///调度表集合 + /// + public ObservableCollection ListCANScheduleConfigDto + { + get { return _ListCANScheduleConfigDto; } + set { _ListCANScheduleConfigDto = value; RaisePropertyChanged(); } + } + + //private string _SelectedWriteName; ///// ///// 选中的写入的Name @@ -1118,6 +1306,7 @@ namespace CapMachine.Wpf.ViewModels //直接修改 FreeSql.Update(item.Id) .Set(a => a.Name, item.Name) + .Set(a => a.LogicRuleId, item.LogicRuleId) .Set(a => a.DefautValue, item.DefautValue) .ExecuteAffrows(); //ListWriteCanLinRWConfigDto.Remove(SelectedWriteCanLinRWConfigDto); @@ -1148,6 +1337,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/Views/CANConfigView.xaml b/CapMachine.Wpf/Views/CANConfigView.xaml index 5d5b52e..b619098 100644 --- a/CapMachine.Wpf/Views/CANConfigView.xaml +++ b/CapMachine.Wpf/Views/CANConfigView.xaml @@ -406,7 +406,14 @@ FontSize="18" Text="" /> - + + @@ -574,6 +581,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + @@ -632,6 +720,24 @@ Margin="0,0,15,0" HorizontalAlignment="Right" Orientation="Horizontal"> +