diff --git a/CapMachine.Model/CANLIN/CANFdConfigExd.cs b/CapMachine.Model/CANLIN/CANFdConfigExd.cs
new file mode 100644
index 0000000..4425e27
--- /dev/null
+++ b/CapMachine.Model/CANLIN/CANFdConfigExd.cs
@@ -0,0 +1,53 @@
+using FreeSql.DataAnnotations;
+
+namespace CapMachine.Model.CANLIN
+{
+ ///
+ /// CAN和LIN的配置信息数据
+ ///
+ [Table(Name = "CANFdConfigExd")]
+ public class CANFdConfigExd
+ {
+ ///
+ /// 主键
+ ///
+ [Column(IsPrimary = true, IsIdentity = true)]
+ public long Id { get; set; }
+
+ ///
+ /// 数据波特率
+ ///
+ [Column(Name = "DataBaudRate")]
+ public int DataBaudRate { get; set; }
+
+ ///
+ /// 仲裁波特率
+ ///
+ [Column(Name = "ArbBaudRate")]
+ public int ArbBaudRate { get; set; }
+
+ ///
+ /// CAN FD标准 ISO是否启用
+ ///
+ [Column(Name = "ISOEnable")]
+ public bool ISOEnable { get; set; }
+
+ ///
+ /// 终端电阻 是否启用
+ ///
+ [Column(Name = "ResEnable")]
+ public bool ResEnable { get; set; }
+
+ ///
+ /// 周期
+ ///
+ [Column(Name = "Cycle")]
+ public int Cycle { get; set; }
+
+ ///
+ /// Dbc文件路径
+ ///
+ [Column(Name = "DbcPath", IsNullable = false, StringLength = 500)]
+ public string? DbcPath { get; set; }
+ }
+}
diff --git a/CapMachine.Model/CANLIN/CanLinConfigPro.cs b/CapMachine.Model/CANLIN/CanLinConfigPro.cs
index 249ecb8..d754453 100644
--- a/CapMachine.Model/CANLIN/CanLinConfigPro.cs
+++ b/CapMachine.Model/CANLIN/CanLinConfigPro.cs
@@ -44,6 +44,11 @@ namespace CapMachine.Model.CANLIN
public List? CanLinConfigContents { get; set; }
+ ///
+ /// ///////////////////////////////////////////导航属性 LIN 一对一///////////////////////////////////////////////////////
+ ///
+ public long CANFdConfigExdId { get; set; } // 外键字段,必要
+ public CANFdConfigExd CANFdConfigExd { get; set; }
///
/// ///////////////////////////////////////////导航属性 CAN 一对一///////////////////////////////////////////////////////
diff --git a/CapMachine.Model/CANLIN/CanLinEmun.cs b/CapMachine.Model/CANLIN/CanLinEmun.cs
index 42802ed..d13c13b 100644
--- a/CapMachine.Model/CANLIN/CanLinEmun.cs
+++ b/CapMachine.Model/CANLIN/CanLinEmun.cs
@@ -19,6 +19,12 @@ namespace CapMachine.Model.CANLIN
/// LIN
///
LIN = 2,
+
+ ///
+ /// CANFD
+ ///
+ CANFD = 3,
+
}
///
diff --git a/CapMachine.Model/CANLIN/CanLinRWConfig.cs b/CapMachine.Model/CANLIN/CanLinRWConfig.cs
index ca6e539..9957adb 100644
--- a/CapMachine.Model/CANLIN/CanLinRWConfig.cs
+++ b/CapMachine.Model/CANLIN/CanLinRWConfig.cs
@@ -61,5 +61,14 @@ namespace CapMachine.Model.CANLIN
public long CanLinConfigProId { get; set; }
public CanLinConfigPro? CanLinConfigPro { get; set; }
+
+
+
+ public long LogicRuleId { get; set; }
+ ///
+ /// CanLinConfig的逻辑转换规则
+ /// 比如:速度下发的数据SV是4000,但是下发到CAN的值是40,可能是其他的逻辑转换规则,这里就是保存其中的逻辑规则
+ ///
+ public LogicRule? LogicRule { get; set; }
}
}
diff --git a/CapMachine.Model/LogicRule.cs b/CapMachine.Model/LogicRule.cs
new file mode 100644
index 0000000..18675e1
--- /dev/null
+++ b/CapMachine.Model/LogicRule.cs
@@ -0,0 +1,52 @@
+using CapMachine.Model.CANLIN;
+using FreeSql.DataAnnotations;
+
+namespace CapMachine.Model
+{
+ ///
+ /// 逻辑转换规则模型
+ ///
+ [Table(Name = "LogicRule")]
+ public class LogicRule
+ {
+ ///
+ /// 主键ID
+ ///
+ [Column(IsPrimary = true, IsIdentity = true)]
+ public long Id { get; set; }
+
+ ///
+ /// 规则名称
+ ///
+ [Column(Name = "Name", StringLength = 50)]
+ public string? Name { get; set; }
+
+ ///
+ /// 规则描述
+ ///
+ [Column(Name = "Description", StringLength = 200)]
+ public string? Description { get; set; }
+
+ ///
+ /// 规则表达式
+ ///
+ [Column(Name = "Expression", StringLength = 500)]
+ public string? Expression { get; set; }
+
+ ///
+ /// 适用的参数类型(如:转速、功率等)
+ ///
+ [Column(Name = "ParameterType", StringLength = 50)]
+ public string? ParameterType { get; set; }
+
+ [Column(ServerTime = DateTimeKind.Local, CanUpdate = false)]
+ public DateTime CreateTime { get; set; }
+
+ ///
+ /// ///////////////////////////////////////////导航属性///////////////////////////////////////////////////////
+ ///
+
+ public List? CanLinRWConfigs { get; set; }
+
+ }
+}
diff --git a/CapMachine.Wpf/App.xaml.cs b/CapMachine.Wpf/App.xaml.cs
index 851d5d8..c5b0261 100644
--- a/CapMachine.Wpf/App.xaml.cs
+++ b/CapMachine.Wpf/App.xaml.cs
@@ -123,12 +123,13 @@ namespace CapMachine.Wpf
//containerRegistry.RegisterSingleton();
//containerRegistry.RegisterSingleton();
-
+ containerRegistry.RegisterSingleton();
containerRegistry.RegisterSingleton();
containerRegistry.RegisterSingleton();
////注册设备服务
//containerRegistry.RegisterSingleton();
containerRegistry.RegisterSingleton();
+ containerRegistry.RegisterSingleton();
containerRegistry.RegisterSingleton();
containerRegistry.RegisterSingleton();
containerRegistry.RegisterSingleton();
@@ -178,6 +179,7 @@ namespace CapMachine.Wpf
containerRegistry.RegisterForNavigation();
containerRegistry.RegisterForNavigation();
containerRegistry.RegisterForNavigation();
+ containerRegistry.RegisterForNavigation();
containerRegistry.RegisterForNavigation();
@@ -196,6 +198,7 @@ namespace CapMachine.Wpf
containerRegistry.RegisterDialog();
containerRegistry.RegisterDialog();
containerRegistry.RegisterDialog();
+ containerRegistry.RegisterDialog();
containerRegistry.RegisterDialog();
diff --git a/CapMachine.Wpf/CanDrive/CanCmdData.cs b/CapMachine.Wpf/CanDrive/CanCmdData.cs
index 58baba8..f9ecfdb 100644
--- a/CapMachine.Wpf/CanDrive/CanCmdData.cs
+++ b/CapMachine.Wpf/CanDrive/CanCmdData.cs
@@ -1,4 +1,5 @@
-using System;
+using CapMachine.Wpf.Dtos;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -31,5 +32,12 @@ namespace CapMachine.Wpf.CanDrive
/// 没有的话,则给默认值
///
public double SignalCmdValue { get; set; }
+
+ ///
+ /// CanLinConfig的逻辑转换规则
+ /// 比如:速度下发的数据SV是4000,但是下发到CAN的值是40,可能是其他的逻辑转换规则,这里就是保存其中的逻辑规则
+ ///
+ public LogicRuleDto? LogicRuleDto { get; set; }
+
}
}
diff --git a/CapMachine.Wpf/CanDrive/CanFD/DBCParserByFD.cs b/CapMachine.Wpf/CanDrive/CanFD/DBCParserByFD.cs
new file mode 100644
index 0000000..0967da2
--- /dev/null
+++ b/CapMachine.Wpf/CanDrive/CanFD/DBCParserByFD.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CapMachine.Wpf.CanDrive.CanFD
+{
+ ///
+ /// 和DBCParser一样,但用于处理USB设备的DBC文件解析。
+ /// DBCParserByFD类用于处理USB设备的DBC文件解析。
+ ///
+ public class DBCParserByFD
+ {
+ public const Int32 DBC_PARSER_OK = 0;//没有错误
+ public const Int32 DBC_PARSER_FILE_OPEN = (-1);//打开文件出错
+ public const Int32 DBC_PARSER_FILE_FORMAT = (-2);//文件格式错误
+ public const Int32 DBC_PARSER_DEV_DISCONNECT = (-3);//设备未连接
+ public const Int32 DBC_PARSER_HANDLE_ERROR = (-4);//LDF Handle错误
+ public const Int32 DBC_PARSER_GET_INFO_ERROR = (-5);//获取解析后的数据出错
+ public const Int32 DBC_PARSER_DATA_ERROR = (-6);//数据处理错误
+ public const Int32 DBC_PARSER_SLAVE_NACK = (-7);//从机未响应数据
+
+ [DllImport("USB2XXX.dll")]
+ public static extern UInt64 DBC_ParserFile(int DevHandle, StringBuilder pDBCFileName);
+ [DllImport("USB2XXX.dll")]
+ public static extern Int32 DBC_GetMsgQuantity(UInt64 DBCHandle);
+ [DllImport("USB2XXX.dll")]
+ public static extern Int32 DBC_GetMsgName(UInt64 DBCHandle, int index, StringBuilder pMsgName);
+ [DllImport("USB2XXX.dll")]
+ public static extern Int32 DBC_GetMsgSignalQuantity(UInt64 DBCHandle, StringBuilder pMsgName);
+ [DllImport("USB2XXX.dll")]
+ public static extern Int32 DBC_GetMsgSignalName(UInt64 DBCHandle, StringBuilder pMsgName, int index, StringBuilder pSignalName);
+ [DllImport("USB2XXX.dll")]
+ public static extern Int32 DBC_GetMsgPublisher(UInt64 DBCHandle, StringBuilder pMsgName, StringBuilder pPublisher);
+ //设置信号值
+ [DllImport("USB2XXX.dll")]
+ public static extern Int32 DBC_SetSignalValue(UInt64 DBCHandle, StringBuilder pMsgName, StringBuilder pSignalName, double Value);
+ //获取信号值
+ [DllImport("USB2XXX.dll")]
+ public static extern Int32 DBC_GetSignalValue(UInt64 DBCHandle, StringBuilder pMsgName, StringBuilder pSignalName, double[] pValue);
+ [DllImport("USB2XXX.dll")]
+ public static extern Int32 DBC_GetSignalValueStr(UInt64 DBCHandle, StringBuilder pMsgName, StringBuilder pSignalName, StringBuilder pValueStr);
+
+ //将CAN消息数据填充到信号里面
+ [DllImport("USB2XXX.dll")]
+ public static extern Int32 DBC_SyncCANMsgToValue(UInt64 DBCHandle, IntPtr pCANMsg, int MsgLen);
+ [DllImport("USB2XXX.dll")]
+ public static extern Int32 DBC_SyncCANFDMsgToValue(UInt64 DBCHandle, IntPtr pCANFDMsg, int MsgLen);
+ //将信号数据填充到CAN消息里面
+ [DllImport("USB2XXX.dll")]
+ public static extern Int32 DBC_SyncValueToCANMsg(UInt64 DBCHandle, StringBuilder pMsgName, IntPtr pCANMsg);
+ [DllImport("USB2XXX.dll")]
+ public static extern Int32 DBC_SyncValueToCANFDMsg(UInt64 DBCHandle, StringBuilder pMsgName, IntPtr pCANFDMsg);
+ }
+}
diff --git a/CapMachine.Wpf/CanDrive/CanFD/ToomossCanFD.cs b/CapMachine.Wpf/CanDrive/CanFD/ToomossCanFD.cs
new file mode 100644
index 0000000..ca2fbad
--- /dev/null
+++ b/CapMachine.Wpf/CanDrive/CanFD/ToomossCanFD.cs
@@ -0,0 +1,899 @@
+using CapMachine.Wpf.CanDrive.CanFD;
+using CapMachine.Wpf.Models.Tag;
+using CapMachine.Wpf.Services;
+using NPOI.OpenXmlFormats.Wordprocessing;
+using Prism.Ioc;
+using Prism.Mvvm;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using System.Windows.Interop;
+
+namespace CapMachine.Wpf.CanDrive
+{
+ ///
+ /// Toomoss CANFD
+ ///
+ public class ToomossCanFD : BindableBase
+ {
+ private readonly IContainerProvider ContainerProvider;
+
+ ///
+ /// 实例化函数
+ ///
+ public ToomossCanFD(IContainerProvider containerProvider)
+ {
+ ContainerProvider = containerProvider;
+ HighSpeedDataService = ContainerProvider.Resolve();
+ LogService = ContainerProvider.Resolve();
+ //Stopwatch.Frequency表示高精度计时器每秒的计数次数(ticks/秒)每毫秒的ticks数 = 每秒的ticks数 ÷ 1000
+ TicksPerMs = Stopwatch.Frequency / 1000.0;
+ }
+
+ ///
+ /// HighSpeedDataService 实例
+ ///
+ public HighSpeedDataService HighSpeedDataService { get; set; }
+
+ public ILogService LogService { get; set; }
+
+ ///
+ /// 开始CAN的驱动
+ ///
+ public void StartCanDrive()
+ {
+ try
+ {
+ IsExistsDllFile();
+ ScanDevice();
+ OpenDevice();
+ GetDeviceInfo();
+ GetCANConfig();
+ InitCAN();
+ }
+ catch (Exception ex)
+ {
+ LogService.Error(ex.Message);
+ System.Windows.MessageBox.Show($"{ex.Message}", "提示", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Hand);
+ }
+ }
+
+ ///
+ /// 开始Dbc文件写入
+ ///
+ public ObservableCollection StartDbc(string DbcPath)
+ {
+ DBC_Parser(DbcPath);
+ return ListCanFdDbcModel;
+ }
+
+ ///
+ /// Dbc消息集合
+ ///
+ public ObservableCollection ListCanFdDbcModel { get; set; } = new ObservableCollection();
+
+
+ #region 公共变量
+
+ ///
+ /// 仲裁波特率
+ ///
+ public uint ArbBaudRate { get; set; } = 500000;
+
+ ///
+ /// 数据波特率
+ ///
+ public uint DataBaudRate { get; set; } = 2000000;
+
+ ///
+ /// CAN FD标准 ISO是否启用
+ ///
+ public bool ISOEnable { get; set; } = true;
+
+ ///
+ /// 终端电阻 是否启用
+ ///
+ public bool ResEnable { get; set; } = true;
+
+ ///
+ /// 更新配置
+ ///
+ public void UpdateConfig(uint arbBaudRate, uint dataBaudRate, bool iSOEnable, bool resEnable, ushort sendCycle)
+ {
+ ArbBaudRate = arbBaudRate;
+ DataBaudRate = dataBaudRate;
+ ISOEnable = iSOEnable;
+ ResEnable = resEnable;
+ SendCycle = sendCycle;
+ }
+
+ ///
+ /// 设备固件信息
+ ///
+ public USB_DEVICEByFD.DEVICE_INFO DevInfo = new USB_DEVICEByFD.DEVICE_INFO();
+
+ ///
+ /// CAN Config
+ ///
+ USB2CANFD.CANFD_INIT_CONFIG CANConfig = new USB2CANFD.CANFD_INIT_CONFIG();
+
+ ///
+ /// 诊断信息
+ ///
+ public USB2CANFD.CANFD_DIAGNOSTIC CurCANFD_DIAGNOSTIC = new USB2CANFD.CANFD_DIAGNOSTIC();
+
+ ///
+ /// CANFD总线错误信息
+ ///
+ public USB2CANFD.CANFD_BUS_ERROR CurCANFD_BUS_ERROR = new USB2CANFD.CANFD_BUS_ERROR();
+
+ ///
+ /// DBC Handle
+ ///
+ public UInt64 DBCHandle { get; set; }
+
+ ///
+ /// 扫描设备Handle集合
+ ///
+ public Int32[] DevHandles { get; set; } = new Int32[20];
+
+ ///
+ /// 扫描设备Handle
+ ///
+ public Int32 DevHandle { get; set; } = 0;
+
+ ///
+ /// Write CAN Index
+ ///
+ public Byte WriteCANIndex { get; set; } = 0;
+
+ ///
+ /// Read CAN Index
+ ///
+ public Byte ReadCANIndex { get; set; } = 0;
+
+
+ private bool _OpenState;
+ ///
+ /// 打开设备的状态
+ ///
+ public bool OpenState
+ {
+ get { return _OpenState; }
+ set { _OpenState = value; RaisePropertyChanged(); }
+ }
+
+ private bool _DbcParserState;
+ ///
+ /// DBC解析的状态
+ ///
+ public bool DbcParserState
+ {
+ get { return _DbcParserState; }
+ set { _DbcParserState = value; RaisePropertyChanged(); }
+ }
+
+ ///
+ /// 扫描到设备个数
+ ///
+ public Int32 DevNum { get; set; }
+
+ public Int32 ret { get; set; }
+
+ public string dllFilePath { get; set; } = "USB2XXX.dll";
+
+
+ ///
+ /// 消息值Pt
+ ///
+ public IntPtr msgPt { get; set; }
+
+ #endregion
+
+ ///
+ /// ******************【1】*********************
+ /// 是否存在Dll文件
+ ///
+ ///
+ public bool IsExistsDllFile()
+ {
+ if (!File.Exists(dllFilePath))
+ {
+ Console.WriteLine("请先将USB2XXX.dll和libusb-1.0.dll文件复制到exe程序文件输出目录下!");
+ Console.WriteLine("dll文件在‘usb2can_lin_pwm_example/sdk/libs/windows’目录下!");
+ Console.WriteLine("程序是32位的就复制‘x86’目录下文件,程序是64位的就复制‘x86_64’目录下文件!");
+ return false;
+ }
+ return true;
+ }
+
+ ///
+ /// ******************【2】*********************
+ /// 扫描查找设备,并将每个设备的唯一设备号存放到数组中,后面的函数需要用到
+ ///
+ ///
+ public bool ScanDevice()
+ {
+ DevNum = USB_DEVICEByFD.USB_ScanDevice(DevHandles);
+ if (DevNum <= 0)
+ {
+ Console.WriteLine("No device connected!");
+
+ return false;
+ }
+ else
+ {
+ Console.WriteLine("Have {0} device connected!", DevNum);
+ DevHandle = DevHandles[0];//获取第一个设备的设备号
+ return true;
+ }
+ }
+
+ ///
+ /// ******************【3】*********************
+ /// 打开设备
+ ///
+ ///
+ public bool OpenDevice()
+ {
+ //打开设备
+ OpenState = USB_DEVICEByFD.USB_OpenDevice(DevHandle);
+ if (!OpenState)
+ {
+ Console.WriteLine("Open device error!");
+ return false;
+ }
+ else
+ {
+ Console.WriteLine("Open device success!");
+ return true;
+ }
+ }
+
+ ///
+ /// ******************【4】*********************
+ /// 获取设备的固件信息
+ ///
+ ///
+ public bool GetDeviceInfo()
+ {
+ //获取固件信息
+ StringBuilder FuncStr = new StringBuilder(256);
+ OpenState = USB_DEVICEByFD.DEV_GetDeviceInfo(DevHandle, ref DevInfo, FuncStr);
+ if (!OpenState)
+ {
+ Console.WriteLine("Get device infomation error!");
+ return false;
+ }
+ else
+ {
+ Console.WriteLine("Firmware Info:");
+ Console.WriteLine(" Name:" + Encoding.Default.GetString(DevInfo.FirmwareName));
+ Console.WriteLine(" Build Date:" + Encoding.Default.GetString(DevInfo.BuildDate));
+ Console.WriteLine(" Firmware Version:v{0}.{1}.{2}", (DevInfo.FirmwareVersion >> 24) & 0xFF, (DevInfo.FirmwareVersion >> 16) & 0xFF, DevInfo.FirmwareVersion & 0xFFFF);
+ Console.WriteLine(" Hardware Version:v{0}.{1}.{2}", (DevInfo.HardwareVersion >> 24) & 0xFF, (DevInfo.HardwareVersion >> 16) & 0xFF, DevInfo.HardwareVersion & 0xFFFF);
+ Console.WriteLine(" Functions:" + DevInfo.Functions.ToString("X8"));
+ Console.WriteLine(" SerialNumber:" + DevInfo.SerialNumber[0] + DevInfo.SerialNumber[1] + DevInfo.SerialNumber[2]);
+ Console.WriteLine(" Functions String:" + FuncStr);
+ StringBuilder DLLBuildDate = new StringBuilder(256);
+ USB_DEVICEByFD.DEV_GetDllBuildTime(DLLBuildDate);
+ Console.WriteLine(" DLL Build Date:" + DLLBuildDate);
+
+ return true;
+ }
+ }
+
+ ///
+ /// ******************【5】*********************
+ /// 获取设备Config配置
+ ///
+ public void GetCANConfig()
+ {
+ //获取CAN波特率参数
+ ret = USB2CANFD.CANFD_GetCANSpeedArg(DevHandle, ref CANConfig, ArbBaudRate, DataBaudRate);
+ if (ret != USB2CANFD.CANFD_SUCCESS)
+ {
+ Console.WriteLine("Get CAN Speed failed!");
+ return;
+ }
+ else
+ {
+ Console.WriteLine("Get CAN Speed Success!");
+ }
+
+ }
+
+ ///
+ /// ******************【6】*********************
+ /// 初始化CAN
+ ///
+ public void InitCAN()
+ {
+ //初始化CAN
+ CANConfig.ISOCRCEnable = ISOEnable == true ? (byte)1 : (byte)0;//使能ISOCRC
+ CANConfig.ResEnable = ResEnable == true ? (byte)1 : (byte)0;//使能终端电阻
+ ret = USB2CANFD.CANFD_Init(DevHandle, WriteCANIndex, ref CANConfig);
+ if (ret != USB2CANFD.CANFD_SUCCESS)
+ {
+ Console.WriteLine("Config CAN failed!");
+ return;
+ }
+ else
+ {
+ Console.WriteLine("WriteCANIndex Config CAN Success!");
+ }
+
+ ret = USB2CANFD.CANFD_Init(DevHandle, ReadCANIndex, ref CANConfig);
+ if (ret != USB2CANFD.CANFD_SUCCESS)
+ {
+ Console.WriteLine("Config CAN failed!");
+ return;
+ }
+ else
+ {
+ Console.WriteLine("ReadCANIndex Config CAN Success!");
+ }
+ Console.WriteLine("");
+ }
+
+ ///
+ /// ******************【7】*********************
+ /// DBC解析
+ ///
+ public void DBC_Parser(string Path)
+ {
+ //解析DBC文件
+ DBCHandle = DBCParserByFD.DBC_ParserFile(DevHandle, new StringBuilder(Path));
+ if (DBCHandle == 0)
+ {
+ Console.WriteLine("Parser DBC File error!");
+ DbcParserState = false;
+ return;
+ }
+ else
+ {
+ Console.WriteLine("Parser DBC File success!");
+ }
+
+ ListCanFdDbcModel.Clear();
+
+ //打印DBC里面报文和信号相关信息
+ int DBCMsgNum = DBCParserByFD.DBC_GetMsgQuantity(DBCHandle);
+ for (int i = 0; i < DBCMsgNum; i++)
+ {
+ StringBuilder MsgName = new StringBuilder(32);
+ DBCParserByFD.DBC_GetMsgName(DBCHandle, i, MsgName);
+ Console.WriteLine("Msg.Name = {0}", MsgName);
+ int DBCSigNum = DBCParserByFD.DBC_GetMsgSignalQuantity(DBCHandle, MsgName);
+ StringBuilder Publisher = new StringBuilder(32);
+ DBCParserByFD.DBC_GetMsgPublisher(DBCHandle, MsgName, Publisher);
+ Console.Write("Signals:");
+ for (int j = 0; j < DBCSigNum; j++)
+ {
+ StringBuilder SigName = new StringBuilder(32);
+ DBCParserByFD.DBC_GetMsgSignalName(DBCHandle, MsgName, j, SigName);
+ Console.Write("{0} ", SigName);
+
+ //增加信息数据
+ ListCanFdDbcModel.Add(new CanDbcModel()
+ {
+ MsgName = MsgName.ToString(),
+ MsgId = "",
+ SignalName = SigName.ToString(),
+ SignalDesc = "",
+ SignalUnit = "",
+ SignalRtValue = "",
+ Publisher = Publisher.ToString()
+ });
+ }
+ Console.WriteLine("");
+ }
+
+ //Dbc解析成功
+ DbcParserState = true;
+ }
+
+ ///
+ /// 发送CAN数据
+ ///
+ public void SendCanMsg(List CmdData)
+ {
+ var GroupMsg = CmdData.GroupBy(x => x.MsgName);
+ USB2CANFD.CANFD_MSG[] CanMsg = new USB2CANFD.CANFD_MSG[GroupMsg.Count()];
+ for (int i = 0; i < GroupMsg.Count(); i++)
+ {
+ CanMsg[i] = new USB2CANFD.CANFD_MSG();
+ CanMsg[i].Data = new Byte[64];
+ }
+
+ IntPtr msgPt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CANFD.CANFD_MSG)));
+ int Index = 0;
+ //循环给MSG赋值数据
+ foreach (var itemMsg in GroupMsg)
+ {
+ foreach (var itemSignal in itemMsg)
+ {
+ DBCParserByFD.DBC_SetSignalValue(DBCHandle, new StringBuilder(itemMsg.Key), new StringBuilder(itemSignal.SignalName), itemSignal.SignalCmdValue);
+ }
+ DBCParserByFD.DBC_SyncValueToCANFDMsg(DBCHandle, new StringBuilder(itemMsg.Key), msgPt);
+ CanMsg[Index] = (USB2CANFD.CANFD_MSG)Marshal.PtrToStructure(msgPt, typeof(USB2CANFD.CANFD_MSG));
+ Index++;
+ }
+
+ //设置信号值
+ //DBCParser.DBC_SetSignalValue(DBCHandle, new StringBuilder("msg_moto_speed"), new StringBuilder("moto_speed"), 2412);
+ //DBCParser.DBC_SetSignalValue(DBCHandle, new StringBuilder("msg_oil_pressure"), new StringBuilder("oil_pressure"), 980);
+ //DBCParser.DBC_SetSignalValue(DBCHandle, new StringBuilder("msg_speed_can"), new StringBuilder("speed_can"), 120);
+
+ //通过DBC写入数据后生成CanMsg
+ //将信号值填入CAN消息里面
+
+
+ //IntPtr msgPt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CANFD.CANFD_MSG)));
+ //DBCParser.DBC_SyncValueToCANFDMsg(DBCHandle, new StringBuilder("msg_moto_speed"), msgPt);
+ //CanMsg[0] = (USB2CANFD.CANFD_MSG)Marshal.PtrToStructure(msgPt, typeof(USB2CANFD.CANFD_MSG));
+
+ //DBCParser.DBC_SyncValueToCANFDMsg(DBCHandle, new StringBuilder("msg_oil_pressure"), msgPt);
+ //CanMsg[1] = (USB2CANFD.CANFD_MSG)Marshal.PtrToStructure(msgPt, typeof(USB2CANFD.CANFD_MSG));
+
+ //DBCParser.DBC_SyncValueToCANFDMsg(DBCHandle, new StringBuilder("msg_speed_can"), msgPt);
+ //CanMsg[2] = (USB2CANFD.CANFD_MSG)Marshal.PtrToStructure(msgPt, typeof(USB2CANFD.CANFD_MSG));
+
+ //释放申请的临时缓冲区
+ Marshal.FreeHGlobal(msgPt);
+ Console.WriteLine("");
+ //发送CAN数据
+ int SendedNum = USB2CANFD.CANFD_SendMsg(DevHandle, WriteCANIndex, CanMsg, (Int32)CanMsg.Length);
+ if (SendedNum >= 0)
+ {
+ Console.WriteLine("Success send frames:{0}", SendedNum);
+ }
+ else
+ {
+ Console.WriteLine("Send CAN data failed! {0}", SendedNum);
+ }
+ }
+
+
+ #region 精确发送报文数据
+
+ // 添加取消标记源字段用于停止任务
+ private CancellationTokenSource CycleSendCts;
+
+ ///
+ /// 计算每毫秒对应的ticks数(只需计算一次)
+ ///
+ private double TicksPerMs;
+
+ // 类成员变量定义 精确记时用
+ private readonly Stopwatch Stopwatcher = new Stopwatch();
+ private long NextExecutionTime;
+ // 计算需要等待的时间
+ private long CurrentTime;
+ private long DelayTicks;
+ private int DelayMs;
+
+ private static readonly Random _random = new Random();
+
+ ///
+ /// 精确周期发送CAN数据
+ ///
+ public void StartPrecisionCycleSendMsg()
+ {
+ // 创建取消标记源 用于控制任务的取消 允许在需要时通过取消令牌来优雅停止任务
+ var cancellationTokenSource = new CancellationTokenSource();
+ var token = cancellationTokenSource.Token;
+
+ // 保存取消标记,以便在停止时使用
+ CycleSendCts = cancellationTokenSource;//将取消标记源保存到类的成员变量CycleSendCts,这样在外部调用停止方法时可以访问它
+ NextExecutionTime = 0;//初始化NextExecutionTime为0,这个变量用于记录下一次执行的目标时间点
+
+ CycleSendTask = Task.Factory.StartNew(async () =>
+ {
+ try
+ {
+ // 设置当前线程为高优先级
+ Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
+
+ // 初始化完成后开始计时
+ Stopwatcher.Restart();
+ // 预先计算固定值
+ long CycleInTicks = (long)(SendCycle * TicksPerMs);
+ //临时测试用
+ //long lastTicks = Stopwatcher.ElapsedTicks;
+ //IsCycleSend
+ while (IsCycleSend && !token.IsCancellationRequested)
+ {
+ try
+ {
+ // 计算下一次执行时间点 ,将当前设置的发送周期SendCycle(毫秒)转换为Stopwatch的计时单位(tick),累加到NextExecutionTime上
+ NextExecutionTime += CycleInTicks; // 转换为Stopwatch计时单位
+
+ // 获取当前时间点,以Stopwatch的tick为单位
+ CurrentTime = Stopwatcher.ElapsedTicks;
+ //计算需要等待的时间,即目标时间点(NextExecutionTime)与当前时间点(CurrentTime)的差值
+ DelayTicks = NextExecutionTime - CurrentTime;
+
+ // 如果还有等待时间,则等待,只有在目标时间点还未到达时才执行等待
+ if (DelayTicks > 0)
+ {
+ ////此时是需要等待的,那么需要等待多久呢, 将需等待的tick数转换回毫秒
+ DelayMs = (int)(DelayTicks / TicksPerMs);
+ //20这个数据是预估和测试的,可能跟Windows抖动误差就是20ms左右,当然可以不用这个IF()判断,直接SpinWait.SpinUntil(() => Stopwatcher.ElapsedTicks >= NextExecutionTime);但是会导致当前独占一个CPU核心线程
+ //所以设置一个20的阈值,20ms以下的延迟使用SpinWait.SpinUntil进行自旋等待,20ms以上的延迟使用Task.Delay进行异步等待,让CPU不至于一直的独占
+ if (DelayMs <= 20)
+ {
+ SpinWait.SpinUntil(() => Stopwatcher.ElapsedTicks >= NextExecutionTime);
+ }
+ else
+ {
+ ////使用Task.Delay进行异步等待,大部分等待时间通过这种方式完成,避免线程阻塞
+ await Task.Delay(DelayMs - 20, token);
+ //// 使用SpinWait.SpinUntil进行精确的微调等待。自旋等待会占用CPU资源,但能提供更高的定时精度,确保在精确的时间点执行
+ ////上面的Task.Delay可能会因为系统调度等原因导致实际执行时间稍晚于预期,因此在这里使用SpinWait.SpinUntil来确保在精确的时间点执行
+ SpinWait.SpinUntil(() => Stopwatcher.ElapsedTicks >= NextExecutionTime);
+ }
+ }
+
+ // 如果已经超过了计划时间,立即执行并重新校准
+ if (Stopwatcher.ElapsedTicks >= NextExecutionTime + CycleInTicks)
+ {
+ //检测是否发生了严重延迟(超过一个周期)。如果当前时间已经超过了下一次计划时间,则说明系统负载过高或其他原因导致无法按时执行,
+ //此时重置NextExecutionTime为当前时间,避免连续的延迟累积
+ // 严重延迟,重新校准
+ NextExecutionTime = Stopwatcher.ElapsedTicks;
+ Console.WriteLine("定时发送延迟过大,重新校准时间");
+ }
+
+ // 使用Stopwatch记录实际的执行间隔,而不是DateTime
+ //Console.WriteLine($"--实际间隔(ms): {(Stopwatcher.ElapsedTicks - lastTicks) / TicksPerMs:F3}, 目标: {SendCycle}");
+ //lastTicks = Stopwatcher.ElapsedTicks;
+
+ //Console.WriteLine($"--当前时间(毫秒): {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}");
+
+
+ // 执行发送CAN逻辑
+ {
+
+ var GroupMsg = CmdData.GroupBy(x => x.MsgName);
+ USB2CANFD.CANFD_MSG[] CanMsg = new USB2CANFD.CANFD_MSG[GroupMsg.Count()];
+ for (int i = 0; i < GroupMsg.Count(); i++)
+ {
+ CanMsg[i] = new USB2CANFD.CANFD_MSG();
+ CanMsg[i].Data = new Byte[64];
+ }
+
+ IntPtr msgPtSend = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CANFD.CANFD_MSG)));
+ int Index = 0;
+
+ //循环给MSG赋值数据
+ foreach (var itemMsg in GroupMsg)
+ {
+ foreach (var itemSignal in itemMsg)
+ {
+ DBCParserByFD.DBC_SetSignalValue(DBCHandle, new StringBuilder(itemMsg.Key), new StringBuilder(itemSignal.SignalName), itemSignal.SignalCmdValue);
+ }
+ DBCParserByFD.DBC_SyncValueToCANFDMsg(DBCHandle, new StringBuilder(itemMsg.Key), msgPtSend);
+ CanMsg[Index] = (USB2CANFD.CANFD_MSG)Marshal.PtrToStructure(msgPtSend, typeof(USB2CANFD.CANFD_MSG));
+ Index++;
+ }
+
+ //通过DBC写入数据后生成CanMsg
+ //将信号值填入CAN消息里面
+
+ //释放申请的临时缓冲区
+ Marshal.FreeHGlobal(msgPtSend);
+ //CanMsg[0].Flags = 5;
+
+ //发送CAN数据
+ int SendedNum = USB2CANFD.CANFD_SendMsg(DevHandle, WriteCANIndex, CanMsg, (Int32)CanMsg.Length);
+
+ if (SendedNum >= 0)
+ {
+ //Console.WriteLine("Success send frames:{0}", SendedNum);
+ IsSendOk = true;
+ }
+ else
+ {
+ //Console.WriteLine("Send CAN data failed! {0}", SendedNum);
+ IsSendOk = false;
+ }
+ }
+
+ }
+ catch (TaskCanceledException)
+ {
+ // 任务被取消,正常退出
+ break;
+ }
+ catch (Exception ex)
+ {
+ LogService.Error(ex.Message);
+ Console.WriteLine($"CAN周期发送异常: {ex.Message}");
+ // 短暂暂停避免异常情况下CPU占用过高
+ await Task.Delay(10, token);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ // 确保在任何情况下(正常退出、异常、取消)都会停止计时器
+ Stopwatcher.Stop();
+ LogService.Error(ex.Message);
+ // 清理其他可能的资源
+ Console.WriteLine("CAN周期发送任务已结束,资源已清理");
+ }
+ finally
+ {
+ // 确保在任何情况下(正常退出、异常、取消)都会停止计时器
+ Stopwatcher.Stop();
+ }
+
+ }, token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
+ }
+
+ ///
+ /// 获取CAN消息数组中指定位置的数据
+ ///
+ /// 源CAN消息数组
+ /// 要获取的数据索引位置
+ /// 返回指定位置数据的新数组
+ private USB2CANFD.CANFD_MSG[] GetCanMsg(USB2CANFD.CANFD_MSG[] sourceCanMsg, int index)
+ {
+ // 参数检查
+ if (sourceCanMsg == null || sourceCanMsg.Length == 0 || index < 0 || index >= sourceCanMsg.Length)
+ {
+ return new USB2CANFD.CANFD_MSG[0];
+ }
+
+ // 创建单个元素的新数组
+ USB2CANFD.CANFD_MSG[] targetMsg = new USB2CANFD.CANFD_MSG[1];
+ targetMsg[0] = sourceCanMsg[index];
+
+ // 由于CANFD_MSG包含数组字段,需要手动初始化数据数组
+ targetMsg[0].Data = new byte[64];
+ // 复制数据
+ Array.Copy(sourceCanMsg[index].Data, targetMsg[0].Data, sourceCanMsg[index].Data.Length);
+
+ return targetMsg;
+ }
+
+ ///
+ /// 修改停止发送的方法
+ ///
+ public void StopCycleSendMsg()
+ {
+ IsCycleSend = false;
+ CycleSendCts?.Cancel();
+ }
+
+ #endregion
+
+
+ private bool _IsCycleRevice;
+ ///
+ /// 是否循环接收数据
+ ///
+ public bool IsCycleRevice
+ {
+ get { return _IsCycleRevice; }
+ set { _IsCycleRevice = value; RaisePropertyChanged(); }
+ }
+
+
+ private bool _IsCycleSend;
+ ///
+ /// 是否循环发送数据
+ ///
+ public bool IsCycleSend
+ {
+ get { return _IsCycleSend; }
+ set { _IsCycleSend = value; RaisePropertyChanged(); }
+ }
+
+ ///
+ /// 循环发送数据
+ ///
+ public ushort SendCycle { get; set; } = 200;
+
+ ///
+ /// 循环接受数据
+ ///
+ public ushort ReviceCycle { get; set; } = 200;
+
+
+ ///
+ /// CycleRevice 扫描Task
+ ///
+ private static Task CycleReviceTask { get; set; }
+
+ ///
+ /// CycleSend 扫描Task
+ ///
+ private static Task CycleSendTask { get; set; }
+
+ StringBuilder ValueSb = new StringBuilder(16);
+ double[] ValueDouble = new double[5];
+
+ private bool _IsSendOk;
+ ///
+ /// 发送报文是否OK
+ ///
+ public bool IsSendOk
+ {
+ get { return _IsSendOk; }
+ set
+ {
+ if (_IsSendOk != value)
+ {
+ RaisePropertyChanged();
+ _IsSendOk = value;
+ }
+ }
+ }
+
+ ///
+ /// 要发送的数据
+ ///
+ public List CmdData { get; set; } = new List();
+
+ ///
+ /// 循环获取CAN消息
+ ///
+ public void StartCycleReviceCanMsg()
+ {
+ CycleReviceTask = Task.Run(async () =>
+ {
+ //var ret = USB2CANFD.CANFD_StartGetMsg(DevHandle, ReadCANIndex);
+ while (IsCycleRevice)
+ {
+ await Task.Delay(ReviceCycle);
+ try
+ {
+ //另外一个CAN通道读取数据
+ USB2CANFD.CANFD_MSG[] CanMsgBuffer = new USB2CANFD.CANFD_MSG[128];
+ IntPtr msgPtRead = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CANFD.CANFD_MSG)) * CanMsgBuffer.Length);
+ int CanNum = USB2CANFD.CANFD_GetMsg(DevHandle, ReadCANIndex, msgPtRead, CanMsgBuffer.Length);
+ if (CanNum > 0)
+ {
+ Console.WriteLine("Read CanMsgNum = {0}", CanNum);
+ for (int i = 0; i < CanNum; i++)
+ {
+ CanMsgBuffer[i] = (USB2CANFD.CANFD_MSG)Marshal.PtrToStructure((IntPtr)(msgPtRead + i * Marshal.SizeOf(typeof(USB2CANFD.CANFD_MSG))), typeof(USB2CANFD.CANFD_MSG));
+ Console.WriteLine("CanMsg[{0}].ID = 0x{1}", i, CanMsgBuffer[i].ID.ToString("X8"));
+ //Console.WriteLine("CanMsg[{0}].TimeStamp = {1}",i,CanMsgBuffer[i].TimeStamp);
+ Console.Write("CanMsg[{0}].Data = ", i);
+ for (int j = 0; j < CanMsgBuffer[i].DLC; j++)
+ {
+ Console.Write("{0} ", CanMsgBuffer[i].Data[j].ToString("X2"));
+ }
+ Console.WriteLine("");
+ //报文给高速记录的服务
+ HighSpeedDataService.AppendOrUpdateMsg(new Models.HighSpeed.CommMsg()
+ {
+ Category = "CANFD",
+ MsgInfo = "0x" + CanMsgBuffer[i].ID.ToString("X8"),
+ MsgData = BitConverter.ToString(CanMsgBuffer[i].Data),
+ Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")
+ });
+ }
+ }
+ else if (CanNum == 0)
+ {
+ Console.WriteLine("No CAN data!");
+ }
+ else
+ {
+ Console.WriteLine("Get CAN data error!");
+ }
+ Console.WriteLine("");
+
+ //将CAN消息数据填充到信号里面
+ DBCParserByFD.DBC_SyncCANFDMsgToValue(DBCHandle, msgPtRead, CanNum);
+
+ //循环获取消息的数据
+ foreach (var item in ListCanFdDbcModel)
+ {
+ //有配置的名称的,认为是有用的,则需要读取数据
+ //if (!string.IsNullOrEmpty(item.Name))
+ //{
+ //CAN_DBCParser.DBC_GetSignalValueStr(DBCHandle, new StringBuilder(item.MsgName), new StringBuilder(item.SignalName), ValueSb);
+ //double[] ValueDouble;
+ DBCParserByFD.DBC_GetSignalValue(DBCHandle, new StringBuilder(item.MsgName), new StringBuilder(item.SignalName), ValueDouble);
+ //item.SignalRtValueSb = ValueSb;
+ item.SignalRtValue = ValueDouble[0].ToString();
+ //Console.Write(ValueSb.ToString());
+ //}
+ }
+
+ //释放数据缓冲区,必须释放,否则程序运行一段时间后会报内存不足
+ Marshal.FreeHGlobal(msgPtRead);
+ Thread.Sleep(10);
+
+ ////获取信号值并打印出来
+ //StringBuilder ValueStr = new StringBuilder(32);
+ //DBCParserByFD.DBC_GetSignalValueStr(DBCHandle, new StringBuilder("TX1"), new StringBuilder("COM_current_Power"), ValueStr);
+ //Console.WriteLine("COM_current_Power = {0}", ValueStr);
+ //DBCParserByFD.DBC_GetSignalValueStr(DBCHandle, new StringBuilder("TX1"), new StringBuilder("COM_Curr_dc"), ValueStr);
+ //Console.WriteLine("COM_Curr_dc = {0}", ValueStr);
+ }
+ catch (Exception ex)
+ {
+ LogService.Error(ex.Message);
+ //LogService.Info($"时间:{DateTime.Now.ToString()}-【Meter】-{ex.Message}");
+ }
+ }
+ });
+ }
+
+ ///
+ /// 接受CAN消息
+ ///
+ public void ReciveCanMsg()
+ {
+ //另外一个CAN通道读取数据
+ USB2CANFD.CANFD_MSG[] CanMsgBuffer = new USB2CANFD.CANFD_MSG[10];
+ msgPt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CANFD.CANFD_MSG)) * CanMsgBuffer.Length);
+ int CanNum = USB2CANFD.CANFD_GetMsg(DevHandle, ReadCANIndex, msgPt, CanMsgBuffer.Length);
+ if (CanNum > 0)
+ {
+ Console.WriteLine("Read CanMsgNum = {0}", CanNum);
+ for (int i = 0; i < CanNum; i++)
+ {
+ CanMsgBuffer[i] = (USB2CANFD.CANFD_MSG)Marshal.PtrToStructure((IntPtr)(msgPt + i * Marshal.SizeOf(typeof(USB2CANFD.CANFD_MSG))), typeof(USB2CANFD.CANFD_MSG));
+ Console.WriteLine("CanMsg[{0}].ID = 0x{1}", i, CanMsgBuffer[i].ID.ToString("X8"));
+ //Console.WriteLine("CanMsg[{0}].TimeStamp = {1}",i,CanMsgBuffer[i].TimeStamp);
+ Console.Write("CanMsg[{0}].Data = ", i);
+ for (int j = 0; j < CanMsgBuffer[i].DLC; j++)
+ {
+ Console.Write("{0} ", CanMsgBuffer[i].Data[j].ToString("X2"));
+ }
+ Console.WriteLine("");
+ }
+ }
+ else if (CanNum == 0)
+ {
+ Console.WriteLine("No CAN data!");
+ }
+ else
+ {
+ Console.WriteLine("Get CAN data error!");
+ }
+ Console.WriteLine("");
+
+ //将CAN消息数据填充到信号里面
+ DBCParserByFD.DBC_SyncCANFDMsgToValue(DBCHandle, msgPt, CanNum);
+ //获取信号值并打印出来
+ StringBuilder ValueStr = new StringBuilder(32);
+ DBCParserByFD.DBC_GetSignalValueStr(DBCHandle, new StringBuilder("msg_moto_speed"), new StringBuilder("moto_speed"), ValueStr);
+ Console.WriteLine("moto_speed = {0}", ValueStr);
+ DBCParserByFD.DBC_GetSignalValueStr(DBCHandle, new StringBuilder("msg_oil_pressure"), new StringBuilder("oil_pressure"), ValueStr);
+ Console.WriteLine("oil_pressure = {0}", ValueStr);
+ DBCParserByFD.DBC_GetSignalValueStr(DBCHandle, new StringBuilder("msg_speed_can"), new StringBuilder("speed_can"), ValueStr);
+ Console.WriteLine("speed_can = {0}", ValueStr);
+
+ }
+
+
+ ///
+ /// 关闭设备
+ ///
+ public void CloseDevice()
+ {
+ //关闭设备
+ USB_DEVICEByFD.USB_CloseDevice(DevHandle);
+ OpenState = false;
+ DbcParserState = false;
+ IsCycleRevice = false;
+ IsCycleSend = false;
+ }
+
+ }
+}
diff --git a/CapMachine.Wpf/CanDrive/USB2CANFD.cs b/CapMachine.Wpf/CanDrive/CanFD/USB2CANFD.cs
similarity index 100%
rename from CapMachine.Wpf/CanDrive/USB2CANFD.cs
rename to CapMachine.Wpf/CanDrive/CanFD/USB2CANFD.cs
diff --git a/CapMachine.Wpf/CanDrive/CanFD/USB_DEVICEByFD.cs b/CapMachine.Wpf/CanDrive/CanFD/USB_DEVICEByFD.cs
new file mode 100644
index 0000000..66b11c1
--- /dev/null
+++ b/CapMachine.Wpf/CanDrive/CanFD/USB_DEVICEByFD.cs
@@ -0,0 +1,143 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CapMachine.Wpf.CanDrive.CanFD
+{
+ ///
+ /// 和USB_DEVICE一样,但用于处理USB设备的CAN FD协议。
+ ///
+ public class USB_DEVICEByFD
+ {
+ //定义电压输出值
+ public const Byte POWER_LEVEL_NONE = 0; //不输出
+ public const Byte POWER_LEVEL_1V8 = 1; //输出1.8V
+ public const Byte POWER_LEVEL_2V5 = 2; //输出2.5V
+ public const Byte POWER_LEVEL_3V3 = 3; //输出3.3V
+ public const Byte POWER_LEVEL_5V0 = 4; //输出5.0V
+ //设备信息定义
+ public struct DEVICE_INFO
+ {
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
+ public Byte[] FirmwareName; //固件名称字符串
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
+ public Byte[] BuildDate; //固件编译时间字符串
+ public UInt32 HardwareVersion;//硬件版本号
+ public UInt32 FirmwareVersion;//固件版本号
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ public UInt32[] SerialNumber; //适配器序列号
+ public UInt32 Functions; //适配器当前具备的功能
+ }
+ //方法定义
+ /**
+ * @brief 初始化USB设备,并扫描设备连接数,必须调用
+ * @param pDevHandle 每个设备的设备号存储地址
+ * @retval 扫描到的设备数量
+ */
+ [DllImport("USB2XXX.dll")]
+ public static extern Int32 USB_ScanDevice(Int32[] pDevHandle);
+ /**
+ * @brief 打开设备,必须调用
+ * @param DevHandle 设备索引号
+ * @retval 打开设备的状态
+ */
+ [DllImport("USB2XXX.dll")]
+ public static extern bool USB_OpenDevice(Int32 DevHandle);
+ /**
+ * @brief 关闭设备
+ * @param DevHandle 设备索引号
+ * @retval 关闭设备的状态
+ */
+ [DllImport("USB2XXX.dll")]
+ public static extern bool USB_CloseDevice(Int32 DevHandle);
+ /**
+ * @brief 复位设备程序,复位后需要重新调用USB_ScanDevice,USB_OpenDevice函数
+ * @param DevHandle 设备索引号
+ * @retval 复位设备的状态
+ */
+ [DllImport("USB2XXX.dll")]
+ public static extern bool USB_ResetDevice(Int32 DevHandle);
+
+ /**
+ * @brief 检测到USB断开连接后,重新连接设备
+ * @param DevHandle 设备号
+ * @retval 重连状态
+ */
+ [DllImport("USB2XXX.dll")]
+ public static extern bool USB_RetryConnect(Int32 DevHandle);
+
+ /**
+ * @brief 获取设备信息,比如设备名称,固件版本号,设备序号,设备功能说明字符串等
+ * @param DevHandle 设备索引号
+ * @param pDevInfo 设备信息存储结构体指针
+ * @param pFunctionStr 设备功能说明字符串
+ * @retval 获取设备信息的状态
+ */
+ [DllImport("USB2XXX.dll")]
+ public static extern bool DEV_GetDeviceInfo(Int32 DevHandle, ref DEVICE_INFO pDevInfo, StringBuilder pFunctionStr);
+ /**
+ * @brief 擦出用户区数据
+ * @param DevHandle 设备索引号
+ * @retval 用户区数据擦出状态
+ */
+ [DllImport("USB2XXX.dll")]
+ public static extern bool DEV_EraseUserData(Int32 DevHandle);
+
+ /**
+ * @brief 向用户区域写入用户自定义数据,写入数据之前需要调用擦出函数将数据擦出
+ * @param DevHandle 设备索引号
+ * @param OffsetAddr 数据写入偏移地址,起始地址为0x00,用户区总容量为0x10000字节,也就是64KBye
+ * @param pWriteData 用户数据缓冲区首地址
+ * @param DataLen 待写入的数据字节数
+ * @retval 写入用户自定义数据状态
+ */
+ [DllImport("USB2XXX.dll")]
+ public static extern bool DEV_WriteUserData(Int32 DevHandle, Int32 OffsetAddr, byte[] pWriteData, Int32 DataLen);
+
+ /**
+ * @brief 从用户自定义数据区读出数据
+ * @param DevHandle 设备索引号
+ * @param OffsetAddr 数据写入偏移地址,起始地址为0x00,用户区总容量为0x10000字节,也就是64KBye
+ * @param pReadData 用户数据缓冲区首地址
+ * @param DataLen 待读出的数据字节数
+ * @retval 读出用户自定义数据的状态
+ */
+ [DllImport("USB2XXX.dll")]
+ public static extern bool DEV_ReadUserData(Int32 DevHandle, Int32 OffsetAddr, byte[] pReadData, Int32 DataLen);
+
+ /**
+ * @brief 设置可变电压输出引脚输出电压值
+ * @param DevHandle 设备索引号
+ * @param PowerLevel 输出电压值
+ * @retval 设置输出电压状态
+ */
+ [DllImport("USB2XXX.dll")]
+ public static extern bool DEV_SetPowerLevel(Int32 DevHandle, byte PowerLevel);
+ /**
+ * @brief 或者CAN或者LIN的时间戳原始值
+ * @param DevHandle 设备索引号
+ * @param pTimestamp 时间戳指针
+ * @retval 获取时间戳状态
+ */
+ [DllImport("USB2XXX.dll")]
+ public static extern bool DEV_GetTimestamp(Int32 DevHandle, byte BusType, Int32[] pTimestamp);
+
+ /**
+ * @brief 复位CAN/LIN时间戳,需要在初始化CAN/LIN之后调用
+ * @param DevHandle 设备索引号
+ * @retval 复位时间戳状态
+ */
+ [DllImport("USB2XXX.dll")]
+ public static extern bool DEV_ResetTimestamp(Int32 DevHandle);
+ /**
+ * @brief 获取dll编译日期
+ * @param pDateTime 输出DLL编译日期字符串
+ * @retval 获取dll编译日期字符串
+ */
+ [DllImport("USB2XXX.dll")]
+ public static extern bool DEV_GetDllBuildTime(StringBuilder pDateTime);
+ }
+}
diff --git a/CapMachine.Wpf/CanDrive/ToomossCanFD.cs b/CapMachine.Wpf/CanDrive/ToomossCanFD.cs
deleted file mode 100644
index a84245b..0000000
--- a/CapMachine.Wpf/CanDrive/ToomossCanFD.cs
+++ /dev/null
@@ -1,511 +0,0 @@
-using CapMachine.Wpf.Models.Tag;
-using NPOI.OpenXmlFormats.Wordprocessing;
-using Prism.Mvvm;
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-using System.Windows.Interop;
-
-namespace CapMachine.Wpf.CanDrive
-{
- ///
- /// Toomoss CAN
- ///
- public class ToomossCanFD : BindableBase
- {
- ///
- /// 实例化函数
- ///
- public ToomossCanFD()
- {
-
- }
-
- ///
- /// 开始CAN的驱动
- ///
- public void StartCanDrive()
- {
- IsExistsDllFile();
- ScanDevice();
- OpenDevice();
- GetDeviceInfo();
- GetCANConfig();
- InitCAN();
-
- }
-
- ///
- /// 开始Dbc文件写入
- ///
- public void StartDbc(string DbcPath)
- {
- DBC_Parser(DbcPath);
- }
-
- ///
- /// Dbc消息集合
- ///
- public ObservableCollection ListCanDbcModel { get; set; } = new ObservableCollection();
-
-
- #region 公共变量
-
- ///
- /// 设备固件信息
- ///
- public USB_DEVICE.DEVICE_INFO DevInfo = new USB_DEVICE.DEVICE_INFO();
-
- ///
- /// CAN Config
- ///
- USB2CANFD.CANFD_INIT_CONFIG CANConfig = new USB2CANFD.CANFD_INIT_CONFIG();
-
- ///
- /// DBC Handle
- ///
- public UInt64 DBCHandle { get; set; }
-
- ///
- /// 扫描设备Handle集合
- ///
- public Int32[] DevHandles { get; set; } = new Int32[20];
-
- ///
- /// 扫描设备Handle
- ///
- public Int32 DevHandle { get; set; } = 0;
- ///
- /// Write CAN Index
- ///
- public Byte WriteCANIndex { get; set; } = 0;
-
- ///
- /// Read CAN Index
- ///
- public Byte ReadCANIndex { get; set; } = 1;
-
-
- private bool _OpenState;
- ///
- /// 打开设备的状态
- ///
- public bool OpenState
- {
- get { return _OpenState; }
- set { _OpenState = value; RaisePropertyChanged(); }
- }
-
-
- ///
- /// 扫描到设备个数
- ///
- public Int32 DevNum { get; set; }
-
- public Int32 ret { get; set; }
-
- public string dllFilePath { get; set; } = "USB2XXX.dll";
-
-
- ///
- /// 消息值Pt
- ///
- public IntPtr msgPt { get; set; }
-
- #endregion
-
- ///
- /// ******************【1】*********************
- /// 是否存在Dll文件
- ///
- ///
- public bool IsExistsDllFile()
- {
- if (!File.Exists(dllFilePath))
- {
- Console.WriteLine("请先将USB2XXX.dll和libusb-1.0.dll文件复制到exe程序文件输出目录下!");
- Console.WriteLine("dll文件在‘usb2can_lin_pwm_example/sdk/libs/windows’目录下!");
- Console.WriteLine("程序是32位的就复制‘x86’目录下文件,程序是64位的就复制‘x86_64’目录下文件!");
- return false;
- }
- return true;
- }
-
- ///
- /// ******************【2】*********************
- /// 扫描查找设备,并将每个设备的唯一设备号存放到数组中,后面的函数需要用到
- ///
- ///
- public bool ScanDevice()
- {
- DevNum = USB_DEVICE.USB_ScanDevice(DevHandles);
- if (DevNum <= 0)
- {
- Console.WriteLine("No device connected!");
-
- return false;
- }
- else
- {
- Console.WriteLine("Have {0} device connected!", DevNum);
- DevHandle = DevHandles[0];//获取第一个设备的设备号
- return true;
- }
- }
-
- ///
- /// ******************【3】*********************
- /// 打开设备
- ///
- ///
- public bool OpenDevice()
- {
- //打开设备
- OpenState = USB_DEVICE.USB_OpenDevice(DevHandle);
- if (!OpenState)
- {
- Console.WriteLine("Open device error!");
- return false;
- }
- else
- {
- Console.WriteLine("Open device success!");
- return true;
- }
- }
-
- ///
- /// ******************【4】*********************
- /// 获取设备的固件信息
- ///
- ///
- public bool GetDeviceInfo()
- {
- //获取固件信息
- StringBuilder FuncStr = new StringBuilder(256);
- OpenState = USB_DEVICE.DEV_GetDeviceInfo(DevHandle, ref DevInfo, FuncStr);
- if (!OpenState)
- {
- Console.WriteLine("Get device infomation error!");
- return false;
- }
- else
- {
- Console.WriteLine("Firmware Info:");
- Console.WriteLine(" Name:" + Encoding.Default.GetString(DevInfo.FirmwareName));
- Console.WriteLine(" Build Date:" + Encoding.Default.GetString(DevInfo.BuildDate));
- Console.WriteLine(" Firmware Version:v{0}.{1}.{2}", (DevInfo.FirmwareVersion >> 24) & 0xFF, (DevInfo.FirmwareVersion >> 16) & 0xFF, DevInfo.FirmwareVersion & 0xFFFF);
- Console.WriteLine(" Hardware Version:v{0}.{1}.{2}", (DevInfo.HardwareVersion >> 24) & 0xFF, (DevInfo.HardwareVersion >> 16) & 0xFF, DevInfo.HardwareVersion & 0xFFFF);
- Console.WriteLine(" Functions:" + DevInfo.Functions.ToString("X8"));
- Console.WriteLine(" Functions String:" + FuncStr);
- StringBuilder DLLBuildDate = new StringBuilder(256);
- USB_DEVICE.DEV_GetDllBuildTime(DLLBuildDate);
- Console.WriteLine(" DLL Build Date:" + DLLBuildDate);
-
- return true;
- }
- }
-
- ///
- /// ******************【5】*********************
- /// 获取设备Config配置
- ///
- public void GetCANConfig()
- {
- //获取CAN波特率参数
- ret = USB2CANFD.CANFD_GetCANSpeedArg(DevHandle, ref CANConfig, 500000, 2000000);
- if (ret != USB2CANFD.CANFD_SUCCESS)
- {
- Console.WriteLine("Get CAN Speed failed!");
- return;
- }
- else
- {
- Console.WriteLine("Get CAN Speed Success!");
- }
-
- }
-
- ///
- /// ******************【6】*********************
- /// 初始化CAN
- ///
- public void InitCAN()
- {
- //初始化CAN
-
- ret = USB2CANFD.CANFD_Init(DevHandle, WriteCANIndex, ref CANConfig);
- if (ret != USB2CANFD.CANFD_SUCCESS)
- {
- Console.WriteLine("Config CAN failed!");
- return;
- }
- else
- {
- Console.WriteLine("WriteCANIndex Config CAN Success!");
- }
-
- ret = USB2CANFD.CANFD_Init(DevHandle, ReadCANIndex, ref CANConfig);
- if (ret != USB2CAN.CAN_SUCCESS)
- {
- Console.WriteLine("Config CAN failed!");
- return;
- }
- else
- {
- Console.WriteLine("ReadCANIndex Config CAN Success!");
- }
- Console.WriteLine("");
- }
-
- ///
- /// ******************【7】*********************
- /// DBC解析
- ///
- public void DBC_Parser(string Path)
- {
- //解析DBC文件
- DBCHandle = CANFD_DBCParser.DBC_ParserFile(DevHandle, new StringBuilder(Path));
- if (DBCHandle == 0)
- {
- Console.WriteLine("Parser DBC File error!");
- return;
- }
- else
- {
- Console.WriteLine("Parser DBC File success!");
- }
-
- ListCanDbcModel.Clear();
-
- //打印DBC里面报文和信号相关信息
- int DBCMsgNum = CANFD_DBCParser.DBC_GetMsgQuantity(DBCHandle);
- for (int i = 0; i < DBCMsgNum; i++)
- {
- StringBuilder MsgName = new StringBuilder(32);
- CANFD_DBCParser.DBC_GetMsgName(DBCHandle, i, MsgName);
- Console.WriteLine("Msg.Name = {0}", MsgName);
- int DBCSigNum = CANFD_DBCParser.DBC_GetMsgSignalQuantity(DBCHandle, MsgName);
- StringBuilder Publisher = new StringBuilder(32);
- CANFD_DBCParser.DBC_GetMsgPublisher(DBCHandle, MsgName, Publisher);
- Console.Write("Signals:");
- for (int j = 0; j < DBCSigNum; j++)
- {
- StringBuilder SigName = new StringBuilder(32);
- CANFD_DBCParser.DBC_GetMsgSignalName(DBCHandle, MsgName, j, SigName);
- Console.Write("{0} ", SigName);
-
- //增加信息数据
- ListCanDbcModel.Add(new CanDbcModel()
- {
- MsgName = MsgName.ToString(),
- MsgId = "",
- SignalName = SigName.ToString(),
- SignalDesc = "",
- SignalUnit = "",
- SignalRtValue = "",
- Publisher = Publisher.ToString()
- });
- }
- Console.WriteLine("");
- }
- }
-
- ///
- /// 发送CAN数据
- ///
- public void SendCanMsg(List CmdData)
- {
- var GroupMsg = CmdData.GroupBy(x => x.MsgName);
- USB2CANFD.CANFD_MSG[] CanMsg = new USB2CANFD.CANFD_MSG[GroupMsg.Count()];
- for (int i = 0; i < GroupMsg.Count(); i++)
- {
- CanMsg[i] = new USB2CANFD.CANFD_MSG();
- CanMsg[i].Data = new Byte[64];
- }
-
- IntPtr msgPt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CANFD.CANFD_MSG)));
- int Index = 0;
- //循环给MSG赋值数据
- foreach (var itemMsg in GroupMsg)
- {
- foreach (var itemSignal in itemMsg)
- {
- CANFD_DBCParser.DBC_SetSignalValue(DBCHandle, new StringBuilder(itemMsg.Key), new StringBuilder(itemSignal.SignalName), itemSignal.SignalCmdValue);
- }
- CANFD_DBCParser.DBC_SyncValueToCANFDMsg(DBCHandle, new StringBuilder(itemMsg.Key), msgPt);
- CanMsg[Index] = (USB2CANFD.CANFD_MSG)Marshal.PtrToStructure(msgPt, typeof(USB2CANFD.CANFD_MSG));
- Index++;
- }
-
- //设置信号值
- //DBCParser.DBC_SetSignalValue(DBCHandle, new StringBuilder("msg_moto_speed"), new StringBuilder("moto_speed"), 2412);
- //DBCParser.DBC_SetSignalValue(DBCHandle, new StringBuilder("msg_oil_pressure"), new StringBuilder("oil_pressure"), 980);
- //DBCParser.DBC_SetSignalValue(DBCHandle, new StringBuilder("msg_speed_can"), new StringBuilder("speed_can"), 120);
-
- //通过DBC写入数据后生成CanMsg
- //将信号值填入CAN消息里面
-
-
- //IntPtr msgPt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CANFD.CANFD_MSG)));
- //DBCParser.DBC_SyncValueToCANFDMsg(DBCHandle, new StringBuilder("msg_moto_speed"), msgPt);
- //CanMsg[0] = (USB2CANFD.CANFD_MSG)Marshal.PtrToStructure(msgPt, typeof(USB2CANFD.CANFD_MSG));
-
- //DBCParser.DBC_SyncValueToCANFDMsg(DBCHandle, new StringBuilder("msg_oil_pressure"), msgPt);
- //CanMsg[1] = (USB2CANFD.CANFD_MSG)Marshal.PtrToStructure(msgPt, typeof(USB2CANFD.CANFD_MSG));
-
- //DBCParser.DBC_SyncValueToCANFDMsg(DBCHandle, new StringBuilder("msg_speed_can"), msgPt);
- //CanMsg[2] = (USB2CANFD.CANFD_MSG)Marshal.PtrToStructure(msgPt, typeof(USB2CANFD.CANFD_MSG));
-
- //释放申请的临时缓冲区
- Marshal.FreeHGlobal(msgPt);
- Console.WriteLine("");
- //发送CAN数据
- int SendedNum = USB2CANFD.CANFD_SendMsg(DevHandle, WriteCANIndex, CanMsg, (Int32)CanMsg.Length);
- if (SendedNum >= 0)
- {
- Console.WriteLine("Success send frames:{0}", SendedNum);
- }
- else
- {
- Console.WriteLine("Send CAN data failed! {0}", SendedNum);
- }
- }
-
- ///
- /// 是否循环接收数据
- ///
- public bool IsCycleRevice { get; set; }
-
- ///
- /// CycleRevice扫描Task
- ///
- private static Task CycleReviceTask { get; set; }
-
- ///
- /// 循环获取CAN消息
- ///
- public void StartCycleReviceCanMsg()
- {
- CycleReviceTask = Task.Run(async () =>
- {
- while (IsCycleRevice)
- {
- await Task.Delay(1000);
- try
- {
- //另外一个CAN通道读取数据
- USB2CANFD.CANFD_MSG[] CanMsgBuffer = new USB2CANFD.CANFD_MSG[10];
- msgPt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CANFD.CANFD_MSG)) * CanMsgBuffer.Length);
- int CanNum = USB2CANFD.CANFD_GetMsg(DevHandle, ReadCANIndex, msgPt, CanMsgBuffer.Length);
- if (CanNum > 0)
- {
- Console.WriteLine("Read CanMsgNum = {0}", CanNum);
- for (int i = 0; i < CanNum; i++)
- {
- CanMsgBuffer[i] = (USB2CANFD.CANFD_MSG)Marshal.PtrToStructure((IntPtr)(msgPt + i * Marshal.SizeOf(typeof(USB2CANFD.CANFD_MSG))), typeof(USB2CANFD.CANFD_MSG));
- Console.WriteLine("CanMsg[{0}].ID = 0x{1}", i, CanMsgBuffer[i].ID.ToString("X8"));
- //Console.WriteLine("CanMsg[{0}].TimeStamp = {1}",i,CanMsgBuffer[i].TimeStamp);
- Console.Write("CanMsg[{0}].Data = ", i);
- for (int j = 0; j < CanMsgBuffer[i].DLC; j++)
- {
- Console.Write("{0} ", CanMsgBuffer[i].Data[j].ToString("X2"));
- }
- Console.WriteLine("");
- }
- }
- else if (CanNum == 0)
- {
- Console.WriteLine("No CAN data!");
- }
- else
- {
- Console.WriteLine("Get CAN data error!");
- }
- Console.WriteLine("");
-
- //将CAN消息数据填充到信号里面
- CANFD_DBCParser.DBC_SyncCANFDMsgToValue(DBCHandle, msgPt, CanNum);
- //获取信号值并打印出来
- StringBuilder ValueStr = new StringBuilder(32);
- CANFD_DBCParser.DBC_GetSignalValueStr(DBCHandle, new StringBuilder("TX1"), new StringBuilder("COM_current_Power"), ValueStr);
- Console.WriteLine("COM_current_Power = {0}", ValueStr);
- CANFD_DBCParser.DBC_GetSignalValueStr(DBCHandle, new StringBuilder("TX1"), new StringBuilder("COM_Curr_dc"), ValueStr);
- Console.WriteLine("COM_Curr_dc = {0}", ValueStr);
- }
- catch (Exception ex)
- {
- //LogService.Info($"时间:{DateTime.Now.ToString()}-【Meter】-{ex.Message}");
- }
- }
- });
- }
-
- ///
- /// 接受CAN消息
- ///
- public void ReciveCanMsg()
- {
- //另外一个CAN通道读取数据
- USB2CANFD.CANFD_MSG[] CanMsgBuffer = new USB2CANFD.CANFD_MSG[10];
- msgPt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CANFD.CANFD_MSG)) * CanMsgBuffer.Length);
- int CanNum = USB2CANFD.CANFD_GetMsg(DevHandle, ReadCANIndex, msgPt, CanMsgBuffer.Length);
- if (CanNum > 0)
- {
- Console.WriteLine("Read CanMsgNum = {0}", CanNum);
- for (int i = 0; i < CanNum; i++)
- {
- CanMsgBuffer[i] = (USB2CANFD.CANFD_MSG)Marshal.PtrToStructure((IntPtr)(msgPt + i * Marshal.SizeOf(typeof(USB2CANFD.CANFD_MSG))), typeof(USB2CANFD.CANFD_MSG));
- Console.WriteLine("CanMsg[{0}].ID = 0x{1}", i, CanMsgBuffer[i].ID.ToString("X8"));
- //Console.WriteLine("CanMsg[{0}].TimeStamp = {1}",i,CanMsgBuffer[i].TimeStamp);
- Console.Write("CanMsg[{0}].Data = ", i);
- for (int j = 0; j < CanMsgBuffer[i].DLC; j++)
- {
- Console.Write("{0} ", CanMsgBuffer[i].Data[j].ToString("X2"));
- }
- Console.WriteLine("");
- }
- }
- else if (CanNum == 0)
- {
- Console.WriteLine("No CAN data!");
- }
- else
- {
- Console.WriteLine("Get CAN data error!");
- }
- Console.WriteLine("");
-
- //将CAN消息数据填充到信号里面
- CANFD_DBCParser.DBC_SyncCANFDMsgToValue(DBCHandle, msgPt, CanNum);
- //获取信号值并打印出来
- StringBuilder ValueStr = new StringBuilder(32);
- CANFD_DBCParser.DBC_GetSignalValueStr(DBCHandle, new StringBuilder("msg_moto_speed"), new StringBuilder("moto_speed"), ValueStr);
- Console.WriteLine("moto_speed = {0}", ValueStr);
- CANFD_DBCParser.DBC_GetSignalValueStr(DBCHandle, new StringBuilder("msg_oil_pressure"), new StringBuilder("oil_pressure"), ValueStr);
- Console.WriteLine("oil_pressure = {0}", ValueStr);
- CANFD_DBCParser.DBC_GetSignalValueStr(DBCHandle, new StringBuilder("msg_speed_can"), new StringBuilder("speed_can"), ValueStr);
- Console.WriteLine("speed_can = {0}", ValueStr);
-
- }
-
-
- ///
- /// 关闭设备
- ///
- public void CloseDevice()
- {
- //关闭设备
- USB_DEVICE.USB_CloseDevice(DevHandle);
- OpenState = false;
- }
-
- }
-}
diff --git a/CapMachine.Wpf/CapMachine.Wpf.csproj b/CapMachine.Wpf/CapMachine.Wpf.csproj
index 601c025..98c763e 100644
--- a/CapMachine.Wpf/CapMachine.Wpf.csproj
+++ b/CapMachine.Wpf/CapMachine.Wpf.csproj
@@ -664,6 +664,7 @@
+
diff --git a/CapMachine.Wpf/Dtos/CANFdConfigExdDto.cs b/CapMachine.Wpf/Dtos/CANFdConfigExdDto.cs
new file mode 100644
index 0000000..8d4d873
--- /dev/null
+++ b/CapMachine.Wpf/Dtos/CANFdConfigExdDto.cs
@@ -0,0 +1,77 @@
+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 CANFdConfigExdDto : BindableBase
+ {
+ ///
+ /// 主键
+ ///
+ public long Id { get; set; }
+
+ private int _DataBaudRate;
+ ///
+ /// 数据波特率
+ ///
+ public int DataBaudRate
+ {
+ get { return _DataBaudRate; }
+ set { _DataBaudRate = value; RaisePropertyChanged(); }
+ }
+
+ private int _ArbBaudRate;
+ ///
+ /// 仲裁波特率
+ ///
+ public int ArbBaudRate
+ {
+ get { return _ArbBaudRate; }
+ set { _ArbBaudRate = value; RaisePropertyChanged(); }
+ }
+
+ private bool _ISOEnable;
+ ///
+ /// ISO 使能
+ ///
+ public bool ISOEnable
+ {
+ get { return _ISOEnable; }
+ set { _ISOEnable = value; RaisePropertyChanged(); }
+ }
+
+ private bool _ResEnable;
+ ///
+ /// 终端电阻使能
+ ///
+ public bool ResEnable
+ {
+ get { return _ResEnable; }
+ set { _ResEnable = value; RaisePropertyChanged(); }
+ }
+
+ private int _Cycle;
+ ///
+ /// 周期
+ ///
+ public int Cycle
+ {
+ get { return _Cycle; }
+ set { _Cycle = value; RaisePropertyChanged(); }
+ }
+
+ private string? _DbcPath;
+ ///
+ /// Dbc文件路径
+ ///
+ public string? DbcPath
+ {
+ get { return _DbcPath; }
+ set { _DbcPath = value; RaisePropertyChanged(); }
+ }
+ }
+}
diff --git a/CapMachine.Wpf/Dtos/CanLinRWConfigDto.cs b/CapMachine.Wpf/Dtos/CanLinRWConfigDto.cs
index 034b598..8be29e9 100644
--- a/CapMachine.Wpf/Dtos/CanLinRWConfigDto.cs
+++ b/CapMachine.Wpf/Dtos/CanLinRWConfigDto.cs
@@ -70,7 +70,12 @@ namespace CapMachine.Wpf.Dtos
set { _DefautValue = value; RaisePropertyChanged(); }
}
-
+ public long LogicRuleId { get; set; }
+ ///
+ /// CanLinConfig的逻辑转换规则
+ /// 比如:速度下发的数据SV是4000,但是下发到CAN的值是40,可能是其他的逻辑转换规则,这里就是保存其中的逻辑规则
+ ///
+ public LogicRuleDto? LogicRuleDto { get; set; }
}
}
diff --git a/CapMachine.Wpf/Dtos/LogicRuleDto.cs b/CapMachine.Wpf/Dtos/LogicRuleDto.cs
new file mode 100644
index 0000000..7392007
--- /dev/null
+++ b/CapMachine.Wpf/Dtos/LogicRuleDto.cs
@@ -0,0 +1,73 @@
+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 LogicRuleDto : BindableBase
+ {
+ ///
+ /// 主键ID
+ ///
+ public int Id { get; set; }
+
+
+ private string _name = string.Empty;
+ ///
+ /// 规则名称
+ ///
+ public string Name
+ {
+ get { return _name; }
+ set { SetProperty(ref _name, value); }
+ }
+
+
+ private string _description = string.Empty;
+ ///
+ /// 规则描述
+ ///
+ public string Description
+ {
+ get { return _description; }
+ set { SetProperty(ref _description, value); }
+ }
+
+ private string _expression = string.Empty;
+ ///
+ /// 规则表达式
+ ///
+ public string Expression
+ {
+ get { return _expression; }
+ set { _expression = value; RaisePropertyChanged(); }
+ }
+
+
+ private string _parameterType = string.Empty;
+ ///
+ /// 适用的参数类型(如:转速、功率等)
+ ///
+ public string ParameterType
+ {
+ get { return _parameterType; }
+ set { SetProperty(ref _parameterType, value); }
+ }
+
+ private DateTime _CreateTime;
+ ///
+ /// 适用的参数类型(如:转速、功率等)
+ ///
+ public DateTime CreateTime
+ {
+ get { return _CreateTime; }
+ set { _CreateTime = value; RaisePropertyChanged(); }
+ }
+ }
+}
diff --git a/CapMachine.Wpf/MapperProfile/CANFdConfigExdProfile.cs b/CapMachine.Wpf/MapperProfile/CANFdConfigExdProfile.cs
new file mode 100644
index 0000000..abafe8f
--- /dev/null
+++ b/CapMachine.Wpf/MapperProfile/CANFdConfigExdProfile.cs
@@ -0,0 +1,19 @@
+using AutoMapper;
+using CapMachine.Model.CANLIN;
+using CapMachine.Wpf.Dtos;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CapMachine.Wpf.MapperProfile
+{
+ public class CANFdConfigExdProfile : Profile
+ {
+ public CANFdConfigExdProfile()
+ {
+ CreateMap().ReverseMap();
+ }
+ }
+}
diff --git a/CapMachine.Wpf/MapperProfile/LogicRuleProfile.cs b/CapMachine.Wpf/MapperProfile/LogicRuleProfile.cs
new file mode 100644
index 0000000..51e2843
--- /dev/null
+++ b/CapMachine.Wpf/MapperProfile/LogicRuleProfile.cs
@@ -0,0 +1,19 @@
+using AutoMapper;
+using CapMachine.Model;
+using CapMachine.Wpf.Dtos;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CapMachine.Wpf.MapperProfile
+{
+ public class LogicRuleProfile : Profile
+ {
+ public LogicRuleProfile()
+ {
+ CreateMap().ReverseMap();
+ }
+ }
+}
diff --git a/CapMachine.Wpf/Models/CanLinRunStateModel.cs b/CapMachine.Wpf/Models/CanLinRunStateModel.cs
index 2241dcf..12d618e 100644
--- a/CapMachine.Wpf/Models/CanLinRunStateModel.cs
+++ b/CapMachine.Wpf/Models/CanLinRunStateModel.cs
@@ -33,6 +33,10 @@ namespace CapMachine.Wpf.Models
SelectedCanLinMsg = "CAN";
CanLinRunState=true;
break;
+ case CanLinEnum.CANFD:
+ SelectedCanLinMsg = "CANFD";
+ CanLinRunState = true;
+ break;
case CanLinEnum.Lin:
SelectedCanLinMsg = "LIN";
CanLinRunState = true;
diff --git a/CapMachine.Wpf/Models/ComEnum.cs b/CapMachine.Wpf/Models/ComEnum.cs
index 8f7b3e9..d2e285c 100644
--- a/CapMachine.Wpf/Models/ComEnum.cs
+++ b/CapMachine.Wpf/Models/ComEnum.cs
@@ -79,6 +79,12 @@ namespace CapMachine.Wpf.Models
/// Lin
///
Lin = 2,
+
+ ///
+ /// CAN FD
+ ///
+ CANFD = 3,
+
}
}
}
diff --git a/CapMachine.Wpf/PrismEvent/LogicRuleChangeEvent.cs b/CapMachine.Wpf/PrismEvent/LogicRuleChangeEvent.cs
new file mode 100644
index 0000000..7721b9d
--- /dev/null
+++ b/CapMachine.Wpf/PrismEvent/LogicRuleChangeEvent.cs
@@ -0,0 +1,14 @@
+using Prism.Events;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CapMachine.Wpf.PrismEvent
+{
+ public class LogicRuleChangeEvent : PubSubEvent
+ {
+
+ }
+}
diff --git a/CapMachine.Wpf/Services/CanFdDriveService.cs b/CapMachine.Wpf/Services/CanFdDriveService.cs
new file mode 100644
index 0000000..bb01213
--- /dev/null
+++ b/CapMachine.Wpf/Services/CanFdDriveService.cs
@@ -0,0 +1,415 @@
+using CapMachine.Model.CANLIN;
+using CapMachine.Wpf.CanDrive;
+using CapMachine.Wpf.Models;
+using CapMachine.Wpf.Models.ProModelPars;
+using ImTools;
+using Prism.Ioc;
+using Prism.Mvvm;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CapMachine.Wpf.Services
+{
+ ///
+ /// Can FD驱动服务
+ ///
+ public class CanFdDriveService : BindableBase
+ {
+ public HighSpeedDataService HighSpeedDataService { get; }
+ public LogicRuleService LogicRuleService { get; }
+
+ ///
+ /// 实例化函数
+ ///
+ public CanFdDriveService(HighSpeedDataService highSpeedDataService, IContainerProvider containerProvider, LogicRuleService logicRuleService)
+ {
+ ToomossCanFDDrive = new ToomossCanFD(containerProvider);
+ //高速数据服务
+ HighSpeedDataService = highSpeedDataService;
+ LogicRuleService = logicRuleService;
+
+ //ToomossCanFDDrive.StartCanDrive();
+ }
+
+ ///
+ /// 当前选中的CanLinConfigPro 程序
+ ///
+ public CanLinConfigPro SelectedCanLinConfigPro { get; set; }
+
+
+ ///
+ /// 图莫斯 CAN Drive
+ /// ToomossCanFDDrive
+ ///
+ public ToomossCanFD ToomossCanFDDrive { get; set; }
+
+ ///
+ /// Dbc消息集合
+ /// 包括读取的实时值和数据
+ ///
+ public ObservableCollection ListCanDbcModel { get; set; } = new ObservableCollection();
+
+ ///
+ /// 初始化CAN的配置信息
+ ///
+ public void InitCanConfig(CanLinConfigPro selectedCanLinConfigPro)
+ {
+ //赋值配置数据
+ SelectedCanLinConfigPro = selectedCanLinConfigPro;
+ //为DBC实时数据关联配置的名称
+ foreach (var item in SelectedCanLinConfigPro.CanLinConfigContents)
+ {
+ var FindData = ListCanDbcModel.FindFirst(a => a.SignalName == item.SignalName);
+ if (FindData != null)
+ {
+ FindData.Name = item.Name;
+ }
+ }
+ }
+
+ ///
+ /// 开始DBC 配置文件 加载
+ ///
+ ///
+ public ObservableCollection StartDbc(string Path)
+ {
+ ListCanDbcModel = ToomossCanFDDrive.StartDbc(Path);
+ return ListCanDbcModel;
+ }
+
+
+ #region 程序驱动CAN
+
+ ///
+ /// 转速 指令数据 实例
+ ///
+ private CanCmdData SpeedCanCmdData { get; set; }
+
+ ///
+ /// 功率限制 指令数据 实例
+ ///
+ private CanCmdData PwLimitCanCmdData { get; set; }
+
+ ///
+ /// 使能 指令数据 实例
+ ///
+ private CanCmdData EnableCanCmdData { get; set; }
+
+ ///
+ /// PTC使能 指令数据 实例
+ ///
+ private CanCmdData PTCEnableCanCmdData { get; set; }
+
+ ///
+ /// PTC功率 指令数据 实例
+ ///
+ private CanCmdData PTCPwCanCmdData { get; set; }
+
+ ///
+ /// PTC水流量 指令数据 实例
+ ///
+ private CanCmdData PTCFlowCanCmdData { get; set; }
+
+ ///
+ /// PTC水温 指令数据 实例
+ ///
+ private CanCmdData PTCWaterTempCanCmdData { get; set; }
+
+
+ ///
+ /// 要发送的CAN指令数据
+ /// 在程序配置好后就确定要发送哪些数据
+ ///
+ public List CmdData { get; set; } = new List();
+
+ ///
+ /// 增加发送的指令数据
+ ///
+ ///
+ public void AddCmdData(CanCmdData SendCanCmdData)
+ {
+ //提取常用的实例数据
+ switch (SendCanCmdData.ConfigName)
+ {
+ case "转速":
+ SpeedCanCmdData = SendCanCmdData;
+ break;
+ case "功率限制":
+ PwLimitCanCmdData = SendCanCmdData;
+ break;
+ case "使能":
+ EnableCanCmdData = SendCanCmdData;
+ break;
+ case "Anti_Sleep":
+ //SpeedCanCmdData = SendCanCmdData;
+ break;
+ case "PTC使能":
+ PTCEnableCanCmdData = SendCanCmdData;
+ break;
+ case "PTC功率":
+ PTCPwCanCmdData = SendCanCmdData;
+ break;
+ case "PTC水流量":
+ PTCFlowCanCmdData = SendCanCmdData;
+ break;
+ case "PTC水温":
+ PTCWaterTempCanCmdData = SendCanCmdData;
+ break;
+ default:
+ break;
+ }
+ //添加到发送数据集合
+ CmdData.Add(SendCanCmdData);
+ }
+
+
+ ///
+ /// 更新速度信息
+ /// 默认是启动
+ ///
+ ///
+ public void UpdateSpeedCmdData(double SpeedData)
+ {
+ if (SpeedCanCmdData != null)
+ {
+ if (SpeedCanCmdData.LogicRuleDto == null)
+ {
+ //没有启动逻辑规则处理
+ SpeedCanCmdData.SignalCmdValue = SpeedData;
+ return;
+ }
+
+ SpeedCanCmdData.SignalCmdValue = LogicRuleService.ApplyExpressionFast(SpeedData, SpeedCanCmdData.LogicRuleDto);
+ }
+ //if (EnableCanCmdData != null)
+ //{
+ // EnableCanCmdData.SignalCmdValue = 1;
+ //}
+ }
+
+ ///
+ /// 更新压缩机使能数据
+ ///
+ ///
+ public void UpdateCapEnableCmdData(bool IsEnable)
+ {
+ if (EnableCanCmdData != null)
+ {
+ EnableCanCmdData.SignalCmdValue = IsEnable ? 1 : 0;
+ }
+ }
+
+
+ ///
+ /// 更新压缩机的功率限制
+ ///
+ ///
+ public void UpdateCapPwLimitCmdData(double PwLimit)
+ {
+ if (PwLimitCanCmdData != null)
+ {
+ if (PwLimitCanCmdData.LogicRuleDto == null)
+ {
+ PwLimitCanCmdData.SignalCmdValue = PwLimit;
+ return;
+ }
+ PwLimitCanCmdData.SignalCmdValue = LogicRuleService.ApplyExpressionFast(PwLimit, PwLimitCanCmdData.LogicRuleDto!);
+ }
+ }
+
+
+ ///
+ /// 更新 PTC使能信号
+ ///
+ ///
+ public void UpdateCapPTCEnableCmdData(bool IsEnable)
+ {
+ if (PTCEnableCanCmdData != null)
+ {
+ PTCEnableCanCmdData.SignalCmdValue = IsEnable ? 1 : 0;
+ }
+ }
+
+ ///
+ /// 更新 PTC功率 信号
+ ///
+ ///
+ public void UpdateCapPTCPwCmdData(double PTCPw)
+ {
+ if (PTCPwCanCmdData != null)
+ {
+ if (PTCPwCanCmdData.LogicRuleDto == null)
+ {
+ PTCPwCanCmdData.SignalCmdValue = PTCPw;
+ return;
+ }
+ PTCPwCanCmdData.SignalCmdValue = LogicRuleService.ApplyExpressionFast(PTCPw, PTCPwCanCmdData.LogicRuleDto!);
+ }
+ }
+
+ ///
+ /// 更新 PTC水流量 信号
+ ///
+ ///
+ public void UpdateCapPTCFlowCmdData(double Flow)
+ {
+ if (PTCFlowCanCmdData != null)
+ {
+ if (PTCFlowCanCmdData.LogicRuleDto == null)
+ {
+ PTCFlowCanCmdData.SignalCmdValue = Flow;
+ return;
+ }
+ PTCFlowCanCmdData.SignalCmdValue = LogicRuleService.ApplyExpressionFast(Flow, PTCFlowCanCmdData.LogicRuleDto!);
+ }
+ }
+
+ ///
+ /// 更新 PTC水温 信号
+ ///
+ ///
+ public void UpdateCapPTCWaterTempCmdData(double WaterTemp)
+ {
+ if (PTCWaterTempCanCmdData != null)
+ {
+ if (PTCWaterTempCanCmdData.LogicRuleDto == null)
+ {
+ PTCWaterTempCanCmdData.SignalCmdValue = WaterTemp;
+ return;
+ }
+ PTCWaterTempCanCmdData.SignalCmdValue = LogicRuleService.ApplyExpressionFast(WaterTemp, PTCWaterTempCanCmdData.LogicRuleDto!);
+ }
+ }
+
+ ///
+ /// 发送消息给CAN 驱动
+ ///
+ public void SendMsgToCanDrive(double SpeedData)
+ {
+ if (ToomossCanFDDrive.OpenState)
+ {
+ if (CmdData.Count > 0)
+ {
+ //更新速度信息
+ UpdateSpeedCmdData(SpeedData);
+
+ ToomossCanFDDrive.SendCanMsg(CmdData);
+ }
+ else
+ {
+ System.Windows.MessageBox.Show("未发现配置的数据内容", "提示", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Hand);
+ }
+ }
+ else
+ {
+ System.Windows.MessageBox.Show("未打开CAN通信,无法发送数据", "提示", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Hand);
+ }
+ }
+
+
+ ///
+ /// 循环发送数据到CAN
+ ///
+ public void CycleSendMsg()
+ {
+ if (ToomossCanFDDrive.OpenState)
+ {
+ if (ToomossCanFDDrive.IsCycleSend == false)
+ {
+ if (CmdData.Count > 0)
+ {
+ ToomossCanFDDrive.IsCycleSend = true;
+ ToomossCanFDDrive.CmdData = CmdData;
+ //ToomossCanFDDrive.StartCycleSendMsg();
+ ToomossCanFDDrive.StartPrecisionCycleSendMsg();
+ }
+ else
+ {
+ System.Windows.MessageBox.Show("未发现配置的数据内容", "提示", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Hand);
+ }
+ }
+ else
+ {
+ ToomossCanFDDrive.IsCycleSend = false;
+ }
+
+ }
+ }
+
+
+
+ ///
+ ///循环接收数据
+ ///
+ public void CycleReciveMsg()
+ {
+ if (ToomossCanFDDrive.OpenState)
+ {
+ if (ToomossCanFDDrive.IsCycleRevice == false)
+ {
+ if (ListCanDbcModel.Count > 0)
+ {
+ ToomossCanFDDrive.IsCycleRevice = true;
+ ToomossCanFDDrive.StartCycleReviceCanMsg();
+ }
+ else
+ {
+ System.Windows.MessageBox.Show("未发现配置的数据内容", "提示", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Hand);
+ }
+ }
+ else
+ {
+ ToomossCanFDDrive.IsCycleRevice = false;
+ }
+ }
+ }
+
+
+ ///
+ /// 获取数据值
+ /// 从DBC中获取数据给数据中心集合
+ ///
+ ///
+ ///
+ public double GetDbcValueByName(string Name)
+ {
+ if (!ToomossCanFDDrive.IsCycleRevice) return 0;
+
+ if (ListCanDbcModel.Any(a => a.Name == Name))
+ {
+ //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 12.3;
+ }
+ return 0;
+ }
+
+ ///
+ /// 速度的数据的获取
+ /// 获取速度数据值
+ /// 从DBC中获取Speed数据给数据中心集合
+ ///
+ ///
+ ///
+ public double GetDbcSpeedValueBySpeedName(string Name)
+ {
+ if (!ToomossCanFDDrive.IsCycleRevice) return 0;
+
+ if (ListCanDbcModel.Any(a => a.Name == Name))
+ {
+ //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 2300;
+ }
+ return 0;
+ }
+
+ #endregion
+
+ }
+}
diff --git a/CapMachine.Wpf/Services/ComActionService.cs b/CapMachine.Wpf/Services/ComActionService.cs
index 21fb180..b1f4438 100644
--- a/CapMachine.Wpf/Services/ComActionService.cs
+++ b/CapMachine.Wpf/Services/ComActionService.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using System.Windows;
namespace CapMachine.Wpf.Services
{
@@ -61,6 +62,14 @@ namespace CapMachine.Wpf.Services
case "过热度/过冷度配置":
ShowSuperHeatCool(msg.Par);
break;
+ case "规则转换":
+ if (SysRunServer.MachineRunState1.IsRunState)
+ {
+ MessageBox.Show("请不要在运行时编辑规则转换,此时更改可能导致运行出错,请停止后再编辑");
+ return;
+ }
+ ShowLogicRule(msg.Par);
+ break;
default:
break;
}
@@ -94,6 +103,41 @@ namespace CapMachine.Wpf.Services
+ ///
+ /// 过热度和过冷度配置弹窗
+ ///
+ private void ShowLogicRule(object par)
+ {
+ //弹窗
+ DialogService.ShowDialog("DialogLogicRuleView", new DialogParameters() { { "Name", par } }, (par) =>
+ {
+ if (par.Result == ButtonResult.OK)
+ {
+ //保存配置信息
+ //PPCService.SaveSuperHeatCoolConfig();
+
+ //是否改变规格
+ var ReturnValue = par.Parameters.GetValue("IsRuleEdit");
+ if (ReturnValue)
+ {
+ MessageBox.Show("检测到你已经改变了规则,CAN或者LIN配置中如果已经加载规则或者连接的话,则会出现错误,那么你需要重启软件");
+ //逻辑可能更改了
+ EventAggregator.GetEvent().Publish("");
+ }
+
+
+ }
+ else if (par.Result == ButtonResult.Cancel)
+ {
+ //取消
+
+ }
+
+ });
+ }
+
+
+
#endregion
diff --git a/CapMachine.Wpf/Services/LogicRuleService.cs b/CapMachine.Wpf/Services/LogicRuleService.cs
new file mode 100644
index 0000000..5adc573
--- /dev/null
+++ b/CapMachine.Wpf/Services/LogicRuleService.cs
@@ -0,0 +1,578 @@
+using AutoMapper;
+using CapMachine.Core;
+using CapMachine.Model;
+using CapMachine.Wpf.Dtos;
+using DynamicExpresso;
+using FreeSql;
+using FreeSql.DataAnnotations;
+using Prism.Mvvm;
+using Syncfusion.Windows.Shared;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace CapMachine.Wpf.Services
+{
+ ///
+ /// 逻辑服务 - 用于处理数据逻辑转换
+ ///
+ public class LogicRuleService : BindableBase
+ {
+ private readonly ILogService LogService;
+ private readonly IFreeSql FreeSql;
+
+ ///
+ /// 逻辑转换规则集合
+ ///
+ public ObservableCollection LogicRuleDtos { get; private set; }
+
+ ///
+ /// DynamicExpresso解释器
+ ///
+ private Interpreter CurInterpreter { get; set; }
+ public IMapper Mapper { get; }
+
+ ///
+ /// 规则表达式缓存(高性能访问)
+ /// Key: 规则名称, Value: 已编译的Lambda表达式
+ ///private readonly ConcurrentDictionary> _expressionCache;
+ ///
+ private readonly ConcurrentDictionary> _expressionCache;
+
+ /////
+ ///// 创建包含指定值的参数数组
+ /////
+ //private Parameter[] CreateParameters(double value)
+ //{
+ // return new Parameter[]
+ // {
+ // new Parameter("value", typeof(double), value)
+ // };
+ //}
+
+ ///
+ /// 创建包含指定值的参数
+ ///
+ private Parameter CreateParameters(double value)
+ {
+ return new Parameter("value", typeof(double), value);
+
+ }
+
+ ///
+ /// 实例化函数
+ ///
+ public LogicRuleService(ILogService logService, IFreeSql freeSql, IMapper mapper)
+ {
+ LogService = logService;
+ FreeSql = freeSql;
+ Mapper = mapper;
+
+ // 初始化集合
+ LogicRuleDtos = new ObservableCollection();
+
+ _expressionCache = new ConcurrentDictionary>();
+
+ // 初始化DynamicExpresso解释器
+ CurInterpreter = new Interpreter();
+
+ try
+ {
+ // 从数据库加载规则
+ LoadRulesFromDatabase();
+
+ }
+ catch (Exception ex)
+ {
+ LogService.Error($"初始化逻辑服务失败: {ex.Message}");
+ }
+ }
+
+ ///
+ /// 从数据库加载规则
+ ///
+ private void LoadRulesFromDatabase()
+ {
+ try
+ {
+ // 从数据库加载规则
+ var dbRules = FreeSql.Select().OrderBy(a => a.Id).ToList();
+ if (dbRules != null && dbRules.Count > 0)
+ {
+ LogicRuleDtos.Clear();
+ _expressionCache.Clear(); // 清空表达式缓存
+
+ foreach (var rule in dbRules)
+ {
+ LogicRuleDtos.Add(Mapper.Map(rule));
+ }
+
+ // 预编译所有表达式
+ WarmUpExpressionCache();
+
+ //LogService.Info($"已从数据库加载并预编译 {dbRules.Count} 条逻辑规则");
+ }
+ else
+ {
+ LogService.Warn("数据库中没有逻辑规则");
+ }
+ }
+ catch (Exception ex)
+ {
+ LogService.Error($"从数据库加载逻辑规则失败: {ex.Message}");
+ throw; // 重新抛出异常以便调用者处理
+ }
+ }
+
+
+ #region 增删改查LogicRule
+
+
+ ///
+ /// 添加新规则
+ ///
+ /// 规则对象
+ public void AddRule(LogicRule rule)
+ {
+ if (string.IsNullOrWhiteSpace(rule.Name))
+ {
+ MessageBox.Show("规则名称不能为空");
+ return;
+ }
+
+ if (string.IsNullOrWhiteSpace(rule.Expression))
+ {
+ MessageBox.Show("规则表达式不能为空");
+ return;
+ }
+
+ if (LogicRuleDtos.Where(a => a.Name == rule.Name).Any())
+ {
+ MessageBox.Show("已经有另一个相同名称的规则了");
+ return;
+ }
+
+ // 验证表达式是否有效
+ if (!ValidateExpression(rule.Expression))
+ {
+ MessageBox.Show("规则表达式验证失败");
+ return;
+ }
+
+ if (InsertRuleToDb(rule, out LogicRule resultInsert))
+ {
+ //此时的resultInsert有新增的ID
+ // 添加规则
+ LogicRuleDtos.Add(Mapper.Map(resultInsert));
+
+ // 预编译并缓存表达式
+ CacheExpression(Mapper.Map(resultInsert));
+ }
+ else
+ {
+ MessageBox.Show("增加数据失败!");
+ return;
+ }
+ //LogService.Info($"添加新规则: {rule.Name}");
+ }
+
+ ///
+ /// 保存规格到数据库中
+ ///
+ ///
+ public bool InsertRuleToDb(LogicRule rule, out LogicRule ResultInsert)
+ {
+ try
+ {
+ // 插入规则到数据库
+ var result = FreeSql.Insert(rule).ExecuteInserted();
+
+ // 检查影响的行数
+ bool success = result.Count > 0;
+
+ if (success)
+ {
+ ResultInsert = result.FirstOrDefault()!;
+ return success;
+ //LogService.Info($"成功插入规则: {rule.Name}");
+
+ // 刷新内存中的规则集合
+ //LoadRulesFromDatabase();
+ }
+ else
+ {
+ LogService.Warn($"插入规则失败: {rule.Name},没有行受影响");
+ ResultInsert = null;
+ return success;
+ }
+
+
+ }
+ catch (Exception ex)
+ {
+ LogService.Error($"插入规则到数据库时发生异常: {ex.Message}");
+ ResultInsert = null;
+ return false;
+ }
+ }
+
+ ///
+ /// 更新规则
+ ///
+ /// 规则对象
+ public void UpdateRule(LogicRule ruleOld, LogicRule rule)
+ {
+ if (string.IsNullOrWhiteSpace(rule.Name))
+ {
+ MessageBox.Show("规则名称不能为空");
+ return;
+ }
+
+ if (string.IsNullOrWhiteSpace(rule.Expression))
+ {
+ MessageBox.Show("规则表达式不能为空");
+ return;
+ }
+
+
+ // 验证表达式是否有效
+ if (!ValidateExpression(rule.Expression))
+ {
+ MessageBox.Show("规则表达式验证失败");
+ return;
+ }
+
+ if (UpdateRuleToDb(rule))
+ {
+ // 更新缓存
+ var updatedDto = LogicRuleDtos.FirstOrDefault(r => r.Id == rule.Id);
+ var insertIndex = LogicRuleDtos.ToList().FindIndex(x => x.Id > rule.Id);
+ if (updatedDto != null)
+ {
+ //移除数据
+ LogicRuleDtos.Remove(updatedDto);
+ if (insertIndex == -1)
+ {
+ LogicRuleDtos.Add(Mapper.Map(rule));
+ }
+ else
+ {
+ // 在找到的位置插入
+ LogicRuleDtos.Insert(insertIndex - 1, Mapper.Map(rule));
+ }
+
+ //有可能更改的是名称,那么新名称的话在_expressionCache中肯定是找不到的,可以用之前的ruleOld
+ _expressionCache.TryRemove(ruleOld.Name!, out _);
+ CacheExpression(updatedDto);
+ }
+ }
+
+ //LogService.Info($"更新规则: {rule.Name}");
+ }
+
+ ///
+ /// 更新规格到数据库中
+ ///
+ ///
+ public bool UpdateRuleToDb(LogicRule rule)
+ {
+ try
+ {
+ // 更新规则到数据库
+ var result = FreeSql.Update()
+ .Set(a => a.Name, rule.Name)
+ .Set(a => a.Description, rule.Description)
+ .Set(a => a.Expression, rule.Expression)
+ .Set(a => a.ParameterType, rule.ParameterType)
+ .Where(r => r.Id == rule.Id)
+ .ExecuteUpdated();
+
+ // 检查影响的行数
+ bool success = result.Count() > 0;
+
+ if (success)
+ {
+ //LogService.Info($"成功更新规则: {rule.Name}");
+
+ }
+ else
+ {
+ //LogService.Warn($"更新规则失败: {rule.Name},没有行受影响");
+ }
+
+ return success;
+ }
+ catch (Exception ex)
+ {
+ //LogService.Error($"更新规则到数据库时发生异常: {ex.Message}");
+ return false;
+ }
+ }
+
+ ///
+ /// 删除规则
+ ///
+ /// 规则名称
+ public void DeleteRule(string ruleName)
+ {
+ var rule = LogicRuleDtos.FirstOrDefault(r => r.Name == ruleName);
+ if (rule == null)
+ {
+ MessageBox.Show("找不到删除的数据");
+ return;
+ }
+
+ var Count = FreeSql.Delete().Where(r => r.Id == rule.Id).ExecuteAffrows();
+ if (Count > 0)
+ {
+ // 删除规则
+ LogicRuleDtos.Remove(rule);
+ // 从缓存中移除表达式
+ _expressionCache.TryRemove(ruleName, out _);
+ }
+
+ //LogService.Info($"删除规则: {ruleName}");
+ }
+
+ ///
+ /// 验证表达式是否有效
+ ///
+ /// 表达式字符串
+ /// 表达式是否有效
+ private bool ValidateExpression(string expression)
+ {
+ try
+ {
+ // 创建测试解释器并直接设置变量
+ var interpreter = new Interpreter()
+ .Reference(typeof(Math)) // 引用Math类
+ .SetVariable("Math", typeof(Math))
+ .SetVariable("value", 100); // 直接设置值变量
+
+ // 尝试编译表达式
+ var lambda = interpreter.Parse(expression);
+
+ // 尝试执行表达式
+ var result = lambda.Invoke();
+
+ // 检查结果是否为数值类型
+ if (result is double doubleResult)
+ {
+ // 验证结果不是NaN或Infinity
+ if (double.IsNaN(doubleResult) || double.IsInfinity(doubleResult))
+ {
+ //LogService.Warn($"表达式执行结果无效 (NaN或Infinity): {expression}");
+ return false;
+ }
+ }
+
+ return true;
+ }
+ catch (Exception ex)
+ {
+ LogService.Warn($"验证表达式失败: {expression}, 错误: {ex.Message}");
+ return false;
+ }
+ }
+
+
+ #endregion
+
+
+ ///
+ /// 根据参数类型获取适用的规则
+ ///
+ /// 参数类型
+ /// 适用的规则列表
+ public IEnumerable GetRulesByParameterType(string parameterType)
+ {
+ return LogicRuleDtos.Where(r => r.ParameterType == parameterType);
+ }
+
+ ///
+ /// 获取指定名称的规则
+ ///
+ /// 规则名称
+ /// 规则对象
+ public LogicRuleDto GetRuleByName(string ruleName)
+ {
+ var rule = LogicRuleDtos.FirstOrDefault(r => r.Name == ruleName);
+ if (rule == null)
+ {
+ throw new KeyNotFoundException($"找不到名为 {ruleName} 的规则");
+ }
+ return rule;
+ }
+
+
+ ///
+ /// 将规则表达式预编译并缓存到字典中
+ ///
+ /// 要缓存的规则
+ private void CacheExpression(LogicRuleDto rule)
+ {
+ if (string.IsNullOrEmpty(rule.Name) || string.IsNullOrEmpty(rule.Expression))
+ {
+ return; // 防止空名称或空表达式
+ }
+
+ try
+ {
+ // ****如下步骤很重要,尝试了很多次才正常运行****
+
+ // 使用已有的CreateParameters方法创建参数声明
+ var parameter = CreateParameters(0); // 值不重要,只是为了获取参数声明
+ // 只解析一次,得到 Lambda 对象
+ var lambda = CurInterpreter.Parse(rule.Expression, parameter); // 只定义参数类型,不传值
+ // 编译为强类型委托
+ var compiledFunc = lambda.Compile>();
+
+ // 存入缓存
+ _expressionCache[rule.Name] = compiledFunc;
+ }
+ catch (Exception ex)
+ {
+ LogService.Error($"缓存规则 {rule.Name} 表达式失败: {ex.Message}");
+ }
+ }
+
+ ///
+ /// 预热表达式缓存 - 预编译所有规则
+ ///
+ private void WarmUpExpressionCache()
+ {
+ foreach (var rule in LogicRuleDtos)
+ {
+ if (!_expressionCache.ContainsKey(rule.Name))
+ {
+ CacheExpression(rule);
+ }
+ }
+ LogService.Info($"已预编译 {_expressionCache.Count} 条规则表达式");
+ }
+
+ ///
+ /// 根据规则应用表达式(高性能版本)
+ ///
+ /// 输入值
+ /// 规则对象
+ /// 转换后的输出值
+ public double ApplyExpression(double value, LogicRuleDto rule)
+ {
+ try
+ {
+ // 尝试从缓存获取预编译的表达式
+ if (!_expressionCache.TryGetValue(rule.Name, out var compiledExpression))
+ {
+ // 如果缓存中没有,则编译并添加到缓存
+ CacheExpression(rule);
+
+ // 再次尝试获取
+ if (!_expressionCache.TryGetValue(rule.Name, out compiledExpression))
+ {
+ // 初始解析表达式(只需执行一次)
+ string expressionText = rule.Expression;
+
+ // 强类型函数
+ Func compiledFunc = (v) =>
+ {
+ // 高性能版本:直接根据公式计算
+ try
+ {
+ if (expressionText.Contains("value"))
+ {
+ var parameters = CreateParameters(v);
+ var lambda = CurInterpreter.Parse(expressionText, parameters);
+ return (double)lambda.Invoke();
+ }
+ else
+ {
+ // 简单表达式使用直接求值
+ return v / 100.0; // 默认处理
+ }
+ }
+ catch
+ {
+ // 出错时返回原值
+ return v;
+ }
+ };
+ // 再次尝试缓存
+ CacheExpression(rule);
+
+ return compiledFunc(value);
+ }
+ }
+
+ // 创建包含实际值的参数
+ var parameter = new Parameter("value", typeof(double), value);
+ // 使用预编译的表达式执行计算(高性能)
+ var convertedValue = (double)compiledExpression.Invoke(value);
+
+ return convertedValue;
+ }
+ catch (Exception ex)
+ {
+ //LogService.Error($"应用规则 {rule.Name} 失败: {ex.Message}");
+ return value; // 出错时返回原始值
+ }
+ }
+
+
+ ///
+ /// 快速的执行数据
+ ///
+ ///
+ ///
+ ///
+ public double ApplyExpressionFast(double value, LogicRuleDto rule)
+ {
+ try
+ {
+ if (!_expressionCache.TryGetValue(rule.Name, out var CurActiveFunc))
+ {
+ CacheExpression(rule);
+ if (!_expressionCache.TryGetValue(rule.Name, out CurActiveFunc))
+ return value;
+ }
+
+ // 直接调用委托,无反射开销
+ return CurActiveFunc(value);
+ }
+ catch
+ {
+ return value;
+ }
+ }
+
+
+ ///
+ /// 如果需要对多个数据应用相同规则,考虑实现批处理版本:
+ ///
+ ///
+ ///
+ ///
+ public IEnumerable ApplyExpressionBatch(IEnumerable values, LogicRuleDto rule)
+ {
+ if (!_expressionCache.TryGetValue(rule.Name, out var func))
+ {
+ CacheExpression(rule);
+ if (!_expressionCache.TryGetValue(rule.Name, out func))
+ return values;
+ }
+
+ // 使用并行处理大量数据
+ return values.AsParallel().Select(v =>
+ {
+ try { return func(v); }
+ catch { return v; }
+ });
+ }
+
+ }
+}
diff --git a/CapMachine.Wpf/Services/MachineRtDataService.cs b/CapMachine.Wpf/Services/MachineRtDataService.cs
index 7b75dd9..837812c 100644
--- a/CapMachine.Wpf/Services/MachineRtDataService.cs
+++ b/CapMachine.Wpf/Services/MachineRtDataService.cs
@@ -35,6 +35,7 @@ namespace CapMachine.Wpf.Services
public AlarmService AlarmService { get; }
public ConfigService ConfigService { get; }
public CanDriveService CanDriveService { get; }
+ public CanFdDriveService CanFdDriveService { get; }
public LinDriveService LinDriveService { get; }
public SysRunService SysRunService { get; }
@@ -118,7 +119,7 @@ namespace CapMachine.Wpf.Services
///
///
public MachineRtDataService(IEventAggregator eventAggregator, AlarmService alarmService, ConfigService configService,
- CanDriveService canDriveService, LinDriveService linDriveService, SysRunService sysRunService)//, AlarmService alarmService
+ CanDriveService canDriveService, CanFdDriveService canFdDriveService, LinDriveService linDriveService, SysRunService sysRunService)//, AlarmService alarmService
{
//ConcurrentDictionary keyValuePairs = new ConcurrentDictionary();
@@ -136,6 +137,7 @@ namespace CapMachine.Wpf.Services
AlarmService = alarmService;
ConfigService = configService;
CanDriveService = canDriveService;
+ CanFdDriveService = canFdDriveService;
LinDriveService = linDriveService;
SysRunService = sysRunService;
@@ -1193,6 +1195,11 @@ namespace CapMachine.Wpf.Services
SiemensDrive.Write(itemTag.Value.PVAddress, (short)CanDriveService.GetDbcSpeedValueBySpeedName("通讯Cmp转速"));
//itemTag.Value.EngPvValue = 0;
break;
+ case CanLinEnum.CANFD:
+ //通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
+ SiemensDrive.Write(itemTag.Value.PVAddress, (short)CanFdDriveService.GetDbcSpeedValueBySpeedName("通讯Cmp转速"));
+ //itemTag.Value.EngPvValue = 0;
+ break;
case CanLinEnum.Lin:
//通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
SiemensDrive.Write(itemTag.Value.PVAddress, (short)LinDriveService.GetLdfSpeedValueBySpeedName("通讯Cmp转速"));
@@ -1212,6 +1219,11 @@ namespace CapMachine.Wpf.Services
SiemensDrive.Write(itemTag.Value.PVAddress, (short)(CanDriveService.GetDbcValueByName("通讯Cmp母线电压") * itemTag.Value.Precision));
//itemTag.Value.EngPvValue = 0;
break;
+ case CanLinEnum.CANFD:
+ //通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
+ SiemensDrive.Write(itemTag.Value.PVAddress, (short)(CanFdDriveService.GetDbcValueByName("通讯Cmp母线电压") * itemTag.Value.Precision));
+ //itemTag.Value.EngPvValue = 0;
+ break;
case CanLinEnum.Lin:
//通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
SiemensDrive.Write(itemTag.Value.PVAddress, (short)(LinDriveService.GetLdfValueByName("通讯Cmp母线电压") * itemTag.Value.Precision));
@@ -1230,6 +1242,11 @@ namespace CapMachine.Wpf.Services
SiemensDrive.Write(itemTag.Value.PVAddress, (short)(CanDriveService.GetDbcValueByName("通讯Cmp母线电流") * itemTag.Value.Precision));
//itemTag.Value.EngPvValue = 0;
break;
+ case CanLinEnum.CANFD:
+ //通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
+ SiemensDrive.Write(itemTag.Value.PVAddress, (short)(CanFdDriveService.GetDbcValueByName("通讯Cmp母线电流") * itemTag.Value.Precision));
+ //itemTag.Value.EngPvValue = 0;
+ break;
case CanLinEnum.Lin:
//通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
SiemensDrive.Write(itemTag.Value.PVAddress, (short)(LinDriveService.GetLdfValueByName("通讯Cmp母线电流") * itemTag.Value.Precision));
@@ -1248,6 +1265,11 @@ namespace CapMachine.Wpf.Services
SiemensDrive.Write(itemTag.Value.PVAddress, (short)(CanDriveService.GetDbcValueByName("通讯Cmp相电流") * itemTag.Value.Precision));
//itemTag.Value.EngPvValue = 0;
break;
+ case CanLinEnum.CANFD:
+ //通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
+ SiemensDrive.Write(itemTag.Value.PVAddress, (short)(CanFdDriveService.GetDbcValueByName("通讯Cmp相电流") * itemTag.Value.Precision));
+ //itemTag.Value.EngPvValue = 0;
+ break;
case CanLinEnum.Lin:
//通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
SiemensDrive.Write(itemTag.Value.PVAddress, (short)(LinDriveService.GetLdfValueByName("通讯Cmp相电流") * itemTag.Value.Precision));
@@ -1266,6 +1288,11 @@ namespace CapMachine.Wpf.Services
SiemensDrive.Write(itemTag.Value.PVAddress, (short)(CanDriveService.GetDbcValueByName("通讯Cmp功率") * itemTag.Value.Precision));
//itemTag.Value.EngPvValue = 0;
break;
+ case CanLinEnum.CANFD:
+ //通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
+ SiemensDrive.Write(itemTag.Value.PVAddress, (short)(CanFdDriveService.GetDbcValueByName("通讯Cmp功率") * itemTag.Value.Precision));
+ //itemTag.Value.EngPvValue = 0;
+ break;
case CanLinEnum.Lin:
//通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
SiemensDrive.Write(itemTag.Value.PVAddress, (short)(LinDriveService.GetLdfValueByName("通讯Cmp功率") * itemTag.Value.Precision));
@@ -1284,6 +1311,11 @@ namespace CapMachine.Wpf.Services
SiemensDrive.Write(itemTag.Value.PVAddress, (short)(CanDriveService.GetDbcValueByName("通讯Cmp芯片温度") * itemTag.Value.Precision));
//itemTag.Value.EngPvValue = 0;
break;
+ case CanLinEnum.CANFD:
+ //通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
+ SiemensDrive.Write(itemTag.Value.PVAddress, (short)(CanFdDriveService.GetDbcValueByName("通讯Cmp芯片温度") * itemTag.Value.Precision));
+ //itemTag.Value.EngPvValue = 0;
+ break;
case CanLinEnum.Lin:
//通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
SiemensDrive.Write(itemTag.Value.PVAddress, (short)(LinDriveService.GetLdfValueByName("通讯Cmp芯片温度") * itemTag.Value.Precision));
@@ -1302,6 +1334,11 @@ namespace CapMachine.Wpf.Services
SiemensDrive.Write(itemTag.Value.PVAddress, (short)(CanDriveService.GetDbcValueByName("通讯Cmp逆变器温度") * itemTag.Value.Precision));
//itemTag.Value.EngPvValue = 0;
break;
+ case CanLinEnum.CANFD:
+ //通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
+ SiemensDrive.Write(itemTag.Value.PVAddress, (short)(CanFdDriveService.GetDbcValueByName("通讯Cmp逆变器温度") * itemTag.Value.Precision));
+ //itemTag.Value.EngPvValue = 0;
+ break;
case CanLinEnum.Lin:
//通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
SiemensDrive.Write(itemTag.Value.PVAddress, (short)(LinDriveService.GetLdfValueByName("通讯Cmp逆变器温度") * itemTag.Value.Precision));
@@ -1320,6 +1357,11 @@ namespace CapMachine.Wpf.Services
SiemensDrive.Write(itemTag.Value.PVAddress, (short)(CanDriveService.GetDbcValueByName("通讯PTC入水温度") * itemTag.Value.Precision));
//itemTag.Value.EngPvValue = 0;
break;
+ case CanLinEnum.CANFD:
+ //通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
+ SiemensDrive.Write(itemTag.Value.PVAddress, (short)(CanFdDriveService.GetDbcValueByName("通讯PTC入水温度") * itemTag.Value.Precision));
+ //itemTag.Value.EngPvValue = 0;
+ break;
case CanLinEnum.Lin:
//通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
SiemensDrive.Write(itemTag.Value.PVAddress, (short)(LinDriveService.GetLdfValueByName("通讯PTC入水温度") * itemTag.Value.Precision));
@@ -1338,6 +1380,11 @@ namespace CapMachine.Wpf.Services
SiemensDrive.Write(itemTag.Value.PVAddress, (short)(CanDriveService.GetDbcValueByName("通讯PTC出水温度") * itemTag.Value.Precision));
//itemTag.Value.EngPvValue = 0;
break;
+ case CanLinEnum.CANFD:
+ //通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
+ SiemensDrive.Write(itemTag.Value.PVAddress, (short)(CanFdDriveService.GetDbcValueByName("通讯PTC出水温度") * itemTag.Value.Precision));
+ //itemTag.Value.EngPvValue = 0;
+ break;
case CanLinEnum.Lin:
//通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
SiemensDrive.Write(itemTag.Value.PVAddress, (short)(LinDriveService.GetLdfValueByName("通讯PTC出水温度") * itemTag.Value.Precision));
@@ -1356,6 +1403,11 @@ namespace CapMachine.Wpf.Services
SiemensDrive.Write(itemTag.Value.PVAddress, (short)(CanDriveService.GetDbcValueByName("通讯PTC峰值电流") * itemTag.Value.Precision));
//itemTag.Value.EngPvValue = 0;
break;
+ case CanLinEnum.CANFD:
+ //通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
+ SiemensDrive.Write(itemTag.Value.PVAddress, (short)(CanFdDriveService.GetDbcValueByName("通讯PTC峰值电流") * itemTag.Value.Precision));
+ //itemTag.Value.EngPvValue = 0;
+ break;
case CanLinEnum.Lin:
//通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
SiemensDrive.Write(itemTag.Value.PVAddress, (short)(LinDriveService.GetLdfValueByName("通讯PTC峰值电流") * itemTag.Value.Precision));
@@ -1374,6 +1426,11 @@ namespace CapMachine.Wpf.Services
SiemensDrive.Write(itemTag.Value.PVAddress, (short)(CanDriveService.GetDbcValueByName("通讯PTC母线电流") * itemTag.Value.Precision));
//itemTag.Value.EngPvValue = 0;
break;
+ case CanLinEnum.CANFD:
+ //通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
+ SiemensDrive.Write(itemTag.Value.PVAddress, (short)(CanFdDriveService.GetDbcValueByName("通讯PTC母线电流") * itemTag.Value.Precision));
+ //itemTag.Value.EngPvValue = 0;
+ break;
case CanLinEnum.Lin:
//通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
SiemensDrive.Write(itemTag.Value.PVAddress, (short)(LinDriveService.GetLdfValueByName("通讯PTC母线电流") * itemTag.Value.Precision));
@@ -1392,6 +1449,11 @@ namespace CapMachine.Wpf.Services
SiemensDrive.Write(itemTag.Value.PVAddress, (short)(CanDriveService.GetDbcValueByName("通讯PTC膜温") * itemTag.Value.Precision));
//itemTag.Value.EngPvValue = 0;
break;
+ case CanLinEnum.CANFD:
+ //通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
+ SiemensDrive.Write(itemTag.Value.PVAddress, (short)(CanFdDriveService.GetDbcValueByName("通讯PTC膜温") * itemTag.Value.Precision));
+ //itemTag.Value.EngPvValue = 0;
+ break;
case CanLinEnum.Lin:
//通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
SiemensDrive.Write(itemTag.Value.PVAddress, (short)(LinDriveService.GetLdfValueByName("通讯PTC膜温") * itemTag.Value.Precision));
@@ -1410,6 +1472,11 @@ namespace CapMachine.Wpf.Services
SiemensDrive.Write(itemTag.Value.PVAddress, (short)(CanDriveService.GetDbcValueByName("通讯PTC模块温度") * itemTag.Value.Precision));
//itemTag.Value.EngPvValue = 0;
break;
+ case CanLinEnum.CANFD:
+ //通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
+ SiemensDrive.Write(itemTag.Value.PVAddress, (short)(CanFdDriveService.GetDbcValueByName("通讯PTC模块温度") * itemTag.Value.Precision));
+ //itemTag.Value.EngPvValue = 0;
+ break;
case CanLinEnum.Lin:
//通信转速 Dbc中间配置名称的转速数据读取出来 给PLC
SiemensDrive.Write(itemTag.Value.PVAddress, (short)(LinDriveService.GetLdfValueByName("通讯PTC模块温度") * itemTag.Value.Precision));
@@ -1444,6 +1511,15 @@ namespace CapMachine.Wpf.Services
itemTag.Value.EngPvValue = CanDriveService.GetDbcValueByName(itemTag.Value.NameNoUnit);
}
break;
+ case CanLinEnum.CANFD:
+ //CAN数据读取 //回读CAN通信的数据到集合中
+ //CAN组合并且在循环接收数据中时,才读取数据
+ if (itemTag.Value.Group == "CANLIN")
+ {
+ //回读CAN通信的DBC集合数据到集合中
+ itemTag.Value.EngPvValue = CanFdDriveService.GetDbcValueByName(itemTag.Value.NameNoUnit);
+ }
+ break;
case CanLinEnum.Lin:
//LIN数据读取 //回读LIN通信的数据到集合中
//LIN组合并且在循环接收数据中时,才读取数据
@@ -1482,6 +1558,11 @@ namespace CapMachine.Wpf.Services
CanDriveService.UpdateSpeedCmdData(itemTag!.Value.EngSvValue);
//itemTag.Value.EngPvValue = 0;
break;
+ case CanLinEnum.CANFD:
+ //获取PLC的SV数据 更新SV的速度值到压缩机
+ CanFdDriveService.UpdateSpeedCmdData(itemTag!.Value.EngSvValue);
+ //itemTag.Value.EngPvValue = 0;
+ break;
case CanLinEnum.Lin:
//获取PLC的SV数据 更新SV的速度值到压缩机
LinDriveService.UpdateSpeedCmdData(itemTag!.Value.EngSvValue);
@@ -1552,6 +1633,10 @@ namespace CapMachine.Wpf.Services
//获取PLC的使能状态,更新到CAN的使能状态
CanDriveService.UpdateCapEnableCmdData(OperateResultValue.Content[0] == 0 ? false : true);
break;
+ case CanLinEnum.CANFD:
+ //获取PLC的使能状态,更新到CAN的使能状态
+ CanFdDriveService.UpdateCapEnableCmdData(OperateResultValue.Content[0] == 0 ? false : true);
+ break;
case CanLinEnum.Lin:
//获取PLC的使能状态,更新到LIN的使能状态
LinDriveService.UpdateCapEnableCmdData(OperateResultValue.Content[0] == 0 ? false : true);
@@ -1583,6 +1668,10 @@ namespace CapMachine.Wpf.Services
//获取PLC的 PTC使能,更新到CAN的 PTC使能
CanDriveService.UpdateCapPTCEnableCmdData(OperateResultValue.Content[20] == 0 ? false : true);
break;
+ case CanLinEnum.CANFD:
+ //获取PLC的 PTC使能,更新到CAN的 PTC使能
+ CanFdDriveService.UpdateCapPTCEnableCmdData(OperateResultValue.Content[20] == 0 ? false : true);
+ break;
case CanLinEnum.Lin:
//获取PLC的 PTC使能,更新到LIN的 PTC使能
LinDriveService.UpdateCapPTCEnableCmdData(OperateResultValue.Content[20] == 0 ? false : true);
@@ -1598,6 +1687,10 @@ namespace CapMachine.Wpf.Services
//获取PLC的 PTC功率,更新到CAN的 PTC功率
CanDriveService.UpdateCapPTCPwCmdData(OperateResultValue.Content[22]);
break;
+ case CanLinEnum.CANFD:
+ //获取PLC的 PTC功率,更新到CAN的 PTC功率
+ CanFdDriveService.UpdateCapPTCPwCmdData(OperateResultValue.Content[22]);
+ break;
case CanLinEnum.Lin:
//获取PLC的 PTC功率,更新到LIN的 PTC功率
LinDriveService.UpdateCapPTCPwCmdData(OperateResultValue.Content[22]);
@@ -1613,6 +1706,10 @@ namespace CapMachine.Wpf.Services
//获取PLC的 PTC水流量信号,更新到CAN的 PTC水流量信号
CanDriveService.UpdateCapPTCFlowCmdData(OperateResultValue.Content[24]);
break;
+ case CanLinEnum.CANFD:
+ //获取PLC的 PTC水流量信号,更新到CAN的 PTC水流量信号
+ CanFdDriveService.UpdateCapPTCFlowCmdData(OperateResultValue.Content[24]);
+ break;
case CanLinEnum.Lin:
//获取PLC的 PTC水流量信号,更新到LIN的 PTC水流量信号
LinDriveService.UpdateCapPTCFlowCmdData(OperateResultValue.Content[24]);
@@ -1628,6 +1725,10 @@ namespace CapMachine.Wpf.Services
//获取PLC的 PTC水温,更新到CAN的 PTC水温
CanDriveService.UpdateCapPTCWaterTempCmdData(OperateResultValue.Content[26]);
break;
+ case CanLinEnum.CANFD:
+ //获取PLC的 PTC水温,更新到CAN的 PTC水温
+ CanFdDriveService.UpdateCapPTCWaterTempCmdData(OperateResultValue.Content[26]);
+ break;
case CanLinEnum.Lin:
//获取PLC的 PTC水温,更新到LIN的 PTC水温
LinDriveService.UpdateCapPTCWaterTempCmdData(OperateResultValue.Content[26]);
diff --git a/CapMachine.Wpf/Services/NavigationMenuService.cs b/CapMachine.Wpf/Services/NavigationMenuService.cs
index db0c4eb..ab57060 100644
--- a/CapMachine.Wpf/Services/NavigationMenuService.cs
+++ b/CapMachine.Wpf/Services/NavigationMenuService.cs
@@ -40,6 +40,10 @@ namespace CapMachine.Wpf.Services
new NavigationItem("SuperHeatCool","过热度/过冷度配置","DialogSuperHeatCoolConfigView"),
//new NavigationItem("Palette","过冷度",""),
}),
+ new NavigationItem("", "规则设置","",new ObservableCollection()
+ {
+ new NavigationItem("Rule","规则转换","DialogLogicRuleView"),
+ }),
//new NavigationItem("", "PID设置","",new ObservableCollection()
//{
// new NavigationItem("Circle","转速PID",""),
@@ -73,6 +77,7 @@ namespace CapMachine.Wpf.Services
//}));
MenuItems.Add(new NavigationItem("", "工艺过程", "MonitorView"));
MenuItems.Add(new NavigationItem("", "CAN配置", "CANConfigView"));
+ MenuItems.Add(new NavigationItem("", "CANFD配置", "CANFDConfigView"));
MenuItems.Add(new NavigationItem("", "LIN配置", "LINConfigView"));
MenuItems.Add(new NavigationItem("", "工艺参数", "ProConfigView"));
MenuItems.Add(new NavigationItem("", "工艺曲线", "RealTimeChartView"));
diff --git a/CapMachine.Wpf/ViewModels/CANFDConfigViewModel.cs b/CapMachine.Wpf/ViewModels/CANFDConfigViewModel.cs
new file mode 100644
index 0000000..86d2cf8
--- /dev/null
+++ b/CapMachine.Wpf/ViewModels/CANFDConfigViewModel.cs
@@ -0,0 +1,1423 @@
+using AutoMapper;
+using CapMachine.Core;
+using CapMachine.Model;
+using CapMachine.Model.CANLIN;
+using CapMachine.Wpf.CanDrive;
+using CapMachine.Wpf.Dtos;
+using CapMachine.Wpf.PrismEvent;
+using CapMachine.Wpf.Services;
+using Ganss.Excel;
+using ImTools;
+using Microsoft.VisualBasic;
+using Microsoft.Win32;
+using NPOI.SS.UserModel.Charts;
+using Prism.Commands;
+using Prism.Events;
+using Prism.Regions;
+using Prism.Services.Dialogs;
+using Syncfusion.Windows.Tools.Controls;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using static CapMachine.Wpf.Models.ComEnum;
+
+namespace CapMachine.Wpf.ViewModels
+{
+ public class CANFDConfigViewModel : NavigationViewModel
+ {
+ public CANFDConfigViewModel(IDialogService dialogService, IFreeSql freeSql,
+ IEventAggregator eventAggregator, IRegionManager regionManager, SysRunService sysRunService,
+ ComActionService actionService, ILogService logService, LogicRuleService logicRuleService,
+ ConfigService configService, CanFdDriveService canFdDriveService,
+ IMapper mapper, MachineRtDataService machineRtDataService)
+ {
+ //LogService = logService;
+ FreeSql = freeSql;
+ EventAggregator = eventAggregator;
+ RegionManager = regionManager;
+ SysRunService = sysRunService;
+ ComActionService = actionService;
+ LogicRuleService = logicRuleService;
+ LogService = logService;
+ ConfigService = configService;
+ CanFdDriveService = canFdDriveService;
+ Mapper = mapper;
+ this.MachineRtDataService = machineRtDataService;
+
+ //MachineDataService = machineDataService;
+ DialogService = dialogService;
+
+ //仲裁波特率
+ ArbBaudRateCbxItems = new ObservableCollection()
+ {
+ new CbxItems(){ Key="10000",Text="10 Kbps"},
+ new CbxItems(){ Key="20000",Text="20 Kbps"},
+ new CbxItems(){ Key="33000",Text="33 Kbps"},
+ new CbxItems(){ Key="50000",Text="50Kbps"},
+ new CbxItems(){ Key="83000",Text="83 Kbps"},
+ new CbxItems(){ Key="100000",Text="100 Kbps"},
+ new CbxItems(){ Key="125000",Text="125 Kbps"},
+ new CbxItems(){ Key="150000",Text="150 Kbps"},
+ new CbxItems(){ Key="200000",Text="200 Kbps"},
+ new CbxItems(){ Key="250000",Text="250 Kbps"},
+ new CbxItems(){ Key="300000",Text="300 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"},
+ };
+
+ //数据波特率
+ 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="转速"},
+ new CbxItems(){ Key="功率限制",Text="功率限制"},
+ new CbxItems(){ Key="使能",Text="使能"},
+ new CbxItems(){ Key="Anti_Sleep",Text="Anti_Sleep"},
+
+ new CbxItems(){ Key="PTC使能",Text="PTC使能"},
+ new CbxItems(){ Key="PTC功率",Text="PTC功率"},
+ new CbxItems(){ Key="PTC水流量",Text="PTC水流量"},
+ new CbxItems(){ Key="PTC水温",Text="PTC水温"},
+ };
+
+ ReadNameCbxItems = new ObservableCollection()
+ {
+ 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芯片温度"},
+
+ 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模块温度"},
+ };
+
+ InitLoadCanConfigPro();
+ //初始化写规则下拉框
+ InitWriteRuleCbx();
+ }
+
+
+ ///
+ /// FreeSQL 实例函数
+ ///
+ public IFreeSql FreeSql { get; }
+ public IEventAggregator EventAggregator { get; }
+ public IRegionManager RegionManager { get; }
+ public SysRunService SysRunService { get; }
+ public ComActionService ComActionService { get; }
+ public LogicRuleService LogicRuleService { get; }
+ public ILogService LogService { get; }
+ public ConfigService ConfigService { get; }
+ public CanFdDriveService CanFdDriveService { get; }
+ public IMapper Mapper { get; }
+ private MachineRtDataService MachineRtDataService { get; }
+
+ ///
+ /// 弹窗服务
+ ///
+ 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
+
+ ///
+ /// 初始化j加载执行方法
+ ///
+ private void InitLoadCanConfigPro()
+ {
+ //CAN配置集合数据
+ canLinConfigPros = FreeSql.Select().Where(a => a.CANLINInfo == CANLIN.CANFD)
+ .Include(a => a.CANFdConfigExd)
+ .IncludeMany(a => a.CanLinConfigContents, then => then.Include(b => b.LogicRule))//,then=> then.Include(b=>b.LogicRule)
+ //.IncludeMany(a => a.CanLinConfigContents)
+ .ToList();
+
+ ListCanLinConfigPro = new ObservableCollection(canLinConfigPros);
+ if (SelectCanLinConfigPro != null)
+ {
+ SelectCanLinConfigPro = canLinConfigPros.Where(a => a.Id == SelectCanLinConfigPro.Id).FirstOrDefault()!;
+ //无数据就返回
+ if (SelectCanLinConfigPro == null) return;
+
+ SelectedCANConfigExdDto = Mapper.Map(SelectCanLinConfigPro!.CANFdConfigExd);
+ if (SelectedCANConfigExdDto != null)
+ {
+ //更新波特率等配置信息
+ CanFdDriveService.ToomossCanFDDrive.UpdateConfig((uint)SelectedCANConfigExdDto.ArbBaudRate,
+ (uint)SelectedCANConfigExdDto.DataBaudRate, SelectedCANConfigExdDto.ISOEnable, SelectedCANConfigExdDto.ResEnable, (ushort)SelectedCANConfigExdDto.Cycle);
+ }
+
+ //配置信息
+ var WirteData = SelectCanLinConfigPro.CanLinConfigContents!.Where(a => a.RWInfo == RW.Write).ToList();
+ if (WirteData != null && WirteData.Count > 0)
+ {
+ ListWriteCanLinRWConfigDto = new ObservableCollection(Mapper.Map>(WirteData));
+
+ //加载把当前的配置信息给指令
+ CanFdDriveService.CmdData.Clear();
+ foreach (var item in WirteData)
+ {
+ CanFdDriveService.AddCmdData(new CanCmdData()
+ {
+ ConfigName = item.Name,
+ MsgName = item.MsgFrameName,
+ SignalName = item.SignalName,
+ SignalCmdValue = double.TryParse(item.DefautValue, out double result) == true ? result : 0,
+ LogicRuleDto = Mapper.Map(item.LogicRule),
+ });
+ //CanFdDriveService.CmdData.Add(new CanCmdData()
+ //{
+ // ConfigName = item.Name,
+ // MsgName = item.MsgFrameName,
+ // SignalName = item.SignalName,
+ // SignalCmdValue = double.TryParse(item.DefautValue, out double result) == true ? result : 0,
+ //});
+ }
+ }
+ var ReadData = SelectCanLinConfigPro.CanLinConfigContents!.Where(a => a.RWInfo == RW.Read).ToList();
+ if (ReadData != null && ReadData.Count > 0)
+ {
+ ListReadCanLinRWConfigDto = new ObservableCollection(Mapper.Map>(ReadData));
+ }
+
+ //匹配选中的SelectCanLinConfigPro.CanLinConfigContents和ListCanDbcModel
+ MatchSeletedAndCanDbcModel();
+ }
+ }
+
+ ///
+ /// 匹配选中的SelectCanLinConfigPro.CanLinConfigContents和ListCanDbcModel
+ /// 为了标注和着色使用
+ ///
+ private void MatchSeletedAndCanDbcModel()
+ {
+ //通过CanLinConfigContents标注ListCanDbcModel的选中状态属性,方便着色
+ if (ListCanDbcModel != null && ListCanDbcModel!.Count() > 0 && SelectCanLinConfigPro.CanLinConfigContents != null && SelectCanLinConfigPro.CanLinConfigContents.Count() > 0)
+ {
+ foreach (var itemCanDbcModel in ListCanDbcModel)
+ {
+ var FindData = SelectCanLinConfigPro.CanLinConfigContents.FindFirst(a => a.SignalName == itemCanDbcModel.SignalName);
+ if (FindData != null)//找到了就标注
+ {
+ switch (FindData.RWInfo)
+ {
+ case RW.Write:
+ itemCanDbcModel.IsSeletedInfo = 1;
+ break;
+ case RW.Read:
+ itemCanDbcModel.IsSeletedInfo = 2;
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ //没有找到了就标注为0
+ itemCanDbcModel.IsSeletedInfo = 0;
+ }
+ }
+ }
+ }
+
+
+
+ private bool _IsCanConfigProActive = false;
+ ///
+ /// CAN 配置是否被激活
+ ///
+ public bool IsCanConfigProActive
+ {
+ get { return _IsCanConfigProActive; }
+ set { _IsCanConfigProActive = value; RaisePropertyChanged(); }
+ }
+
+ private bool _IsCANConfigDatagridActive = true;
+ ///
+ /// CANConfigDatagrid是否被触控
+ /// 关联IsCanConfigProActive 取反
+ ///
+ public bool IsCANConfigDatagridActive
+ {
+ get { return _IsCANConfigDatagridActive; }
+ set { _IsCANConfigDatagridActive = value; RaisePropertyChanged(); }
+ }
+
+ private string _SelectCanLinConfigProConfigName;
+ ///
+ /// 选中的 CanLinConfigPro 名称
+ ///
+ public string SelectCanLinConfigProConfigName
+ {
+ get { return _SelectCanLinConfigProConfigName; }
+ set { _SelectCanLinConfigProConfigName = value; RaisePropertyChanged(); }
+ }
+
+
+ private DelegateCommand _CanLinConfigPromdCmd;
+ ///
+ /// CanConfigPro操作的指令
+ ///
+ public DelegateCommand CanLinConfigPromdCmd
+ {
+ set
+ {
+ _CanLinConfigPromdCmd = value;
+ }
+ get
+ {
+ if (_CanLinConfigPromdCmd == null)
+ {
+ _CanLinConfigPromdCmd = new DelegateCommand((Par) => CanLinConfigPromdCmdMethod(Par));
+ }
+ return _CanLinConfigPromdCmd;
+ }
+ }
+ ///
+ /// CanConfigPro操作的指令方法
+ ///
+ ///
+ private void CanLinConfigPromdCmdMethod(string Par)
+ {
+ switch (Par)
+ {
+ case "Add":
+ //弹窗
+ DialogService.ShowDialog("DialogCanLinConfigCreateView", new DialogParameters() { { "Name", "" } }, (par) =>
+ {
+ if (par.Result == ButtonResult.OK)
+ {
+ //程序名称
+ var ReturnValue = par.Parameters.GetValue("Name");
+
+ //加载默认的数据 CANConfigExd
+ var InsertCANConfigExd = FreeSql.Insert(new CANFdConfigExd()
+ {
+ DataBaudRate = 250,
+ ArbBaudRate = 2000,
+ DbcPath = "请配置DBC路径",
+ Cycle = 100,
+ }).ExecuteInserted();
+
+ //返回数据,刷新Chart
+ var InsertData = FreeSql.Insert(new CanLinConfigPro()
+ {
+ ConfigName = ReturnValue,
+ CANLINInfo = CANLIN.CANFD,
+ CANFdConfigExdId = InsertCANConfigExd.FirstOrDefault()!.Id
+ }).ExecuteInserted();
+ if (InsertData != null)
+ {
+ //加载默认的数据 CanLinRWConfig
+ FreeSql.Insert(new CanLinRWConfig()
+ {
+ SignalName = "Speed",
+ DefautValue = "0",
+ Name = "转速",
+ RWInfo = RW.Write,
+ CanLinConfigProId = InsertData.FirstOrDefault().Id
+ }).ExecuteInserted();
+
+ FreeSql.Insert(new CanLinRWConfig()
+ {
+ SignalName = "Vol",
+ DefautValue = "0",
+ Name = "电压",
+ RWInfo = RW.Read,
+ CanLinConfigProId = InsertData.FirstOrDefault().Id
+
+ }).ExecuteInserted();
+ }
+
+ InitLoadCanConfigPro();
+
+ SelectCanLinConfigPro = canLinConfigPros!.Find(a => a.Id == InsertData.FirstOrDefault()!.Id);
+ }
+ else if (par.Result == ButtonResult.Cancel)
+ {
+ //取消
+
+ }
+
+ });
+
+ break;
+ case "Edit":
+ if (SelectCanLinConfigPro != null)
+ {
+ //弹窗
+ DialogService.ShowDialog("DialogCanLinConfigCreateView", new DialogParameters() { { "Name", SelectCanLinConfigPro.ConfigName } }, (par) =>
+ {
+ if (par.Result == ButtonResult.OK)
+ {
+ //程序名称
+ var ReturnValue = par.Parameters.GetValue("Name");
+
+ FreeSql.Update()
+ .Set(a => a.ConfigName, ReturnValue)
+ .Where(a => a.Id == SelectCanLinConfigPro.Id)
+ .ExecuteAffrows();
+
+ InitLoadCanConfigPro();
+
+ SelectCanLinConfigPro = null;
+ }
+ else if (par.Result == ButtonResult.Cancel)
+ {
+ //取消
+
+ }
+
+ });
+ }
+ else
+ {
+ System.Windows.MessageBox.Show("选中后再操作", "提示", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Hand);
+ }
+ break;
+
+ case "Save":
+
+ case "Delete":
+ if (SelectCanLinConfigPro != null)
+ {
+ var repo = FreeSql.GetRepository();
+ repo.DbContextOptions.EnableCascadeSave = true; //关键设置
+
+ var DeleteData = repo.Select
+ .Include(a => a.CANFdConfigExd)
+ .IncludeMany(a => a.CanLinConfigContents)
+ .Where(a => a.Id == SelectCanLinConfigPro.Id)
+ .ToList();
+
+ repo.Delete(DeleteData);
+ foreach (var item in DeleteData)
+ {
+ FreeSql.Delete(item.CANFdConfigExdId).ExecuteAffrows();
+ }
+ InitLoadCanConfigPro();
+ }
+ else
+ {
+ System.Windows.MessageBox.Show("选中后再操作", "提示", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Hand);
+ }
+ break;
+ case "Active":
+
+ //激活到取消的状态的判断
+ if (IsCanConfigProActive == true)
+ {
+ //控件的激活
+ IsCanConfigProActive = !IsCanConfigProActive;
+ //控件的激活配置信息
+ IsCANConfigDatagridActive = !IsCanConfigProActive;
+
+ return;
+ }
+
+ if ((CanFdDriveService.ToomossCanFDDrive.OpenState == true && CanFdDriveService.ToomossCanFDDrive.DbcParserState == true))
+ {
+ if (SelectCanLinConfigPro != null)
+ {
+ //控件的激活
+ IsCanConfigProActive = !IsCanConfigProActive;
+ //控件的激活配置信息
+ IsCANConfigDatagridActive = !IsCanConfigProActive;
+
+ //当前使用的CAN 配置信息
+ CanFdDriveService.InitCanConfig(SelectCanLinConfigPro);
+
+ InitLoadCanConfigPro();
+ }
+ else
+ {
+ System.Windows.MessageBox.Show("选中后再操作", "提示", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Hand);
+ }
+
+ }
+ else
+ {
+ System.Windows.MessageBox.Show("请确保CAN连接打开和Dbc解析成功后再激活", "提示", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Hand);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ ///
+ /// CAN List集合信息
+ ///
+ private List canLinConfigPros = new List();
+
+
+ private ObservableCollection _ListCanLinConfigPro;
+ ///
+ /// CAN 配置程序集合 ObservableCollection
+ ///
+ public ObservableCollection ListCanLinConfigPro
+ {
+ get { return _ListCanLinConfigPro; }
+ set { _ListCanLinConfigPro = value; RaisePropertyChanged(); }
+ }
+
+ ///
+ /// 选中的CanLinConfigPro
+ ///
+ public CanLinConfigPro SelectCanLinConfigPro { get; set; }
+
+ private DelegateCommand