增加CAN 调度表的配置

This commit is contained in:
2025-09-08 23:04:48 +08:00
parent 6555741b14
commit 2c0575eea7
12 changed files with 1086 additions and 27 deletions

View File

@@ -38,6 +38,11 @@ namespace CapMachine.Model.CANLIN
[Column(Name = "DbcPath", IsNullable = false, StringLength = 500)]
public string? DbcPath { get; set; }
/// <summary>
/// 调度表是否启用
/// </summary>
[Column(Name = "SchEnable")]
public bool SchEnable { get; set; }
///// <summary>

View File

@@ -0,0 +1,55 @@
using FreeSql.DataAnnotations;
namespace CapMachine.Model.CANLIN
{
/// <summary>
/// 调度表的配置
/// 其实这些调度表是在DBC中有的但是图莫斯的驱动没有读取到这些信息
/// 那么我们在系统层面进行操作和保存这些信息
/// </summary>
[Table(Name = "CANScheduleConfig")]
public class CANScheduleConfig
{
/// <summary>
/// 主键
/// </summary>
[Column(IsPrimary = true, IsIdentity = true)]
public long Id { get; set; }
/// <summary>
/// 消息名称
/// </summary>
[Column(Name = "MsgName")]
public string? MsgName { get; set; }
/// <summary>
/// 消息的周期
/// </summary>
[Column(Name = "Cycle")]
public int Cycle { get; set; }
/// <summary>
/// 发送方式
/// </summary>
[Column(Name = "OrderSend")]
public int OrderSend { get; set; }
/// <summary>
/// 调度表的Index
/// //约定每帧对应一个调度表预设5个调度表每个调度表对应一个帧
/// 0-4这个范围的设置Index
/// </summary>
[Column(Name = "SchTabIndex")]
public int SchTabIndex { get; set; }
/// <summary>
/// ///////////////////////////////////////////导航属性///////////////////////////////////////////////////////
/// </summary>
public long CanLinConfigProId { get; set; }
public CanLinConfigPro? CanLinConfigPro { get; set; }
}
}

View File

@@ -44,12 +44,26 @@ namespace CapMachine.Model.CANLIN
public List<CanLinRWConfig>? CanLinConfigContents { get; set; }
/// <summary>
/// ///////////////////////////////////////////导航属性///////////////////////////////////////////////////////
/// </summary>
///CAN 的调度表配置模式
public List<CANScheduleConfig>? CanScheduleConfigs { get; set; }
/// <summary>
/// ///////////////////////////////////////////导航属性///////////////////////////////////////////////////////
/// </summary>
///LIN 的调度表配置模式
public List<LINScheduleConfig>? LinScheduleConfigs { get; set; }
/// <summary>
/// ///////////////////////////////////////////导航属性 LIN 一对一///////////////////////////////////////////////////////
/// </summary>
public long CANFdConfigExdId { get; set; } // 外键字段,必要
public CANFdConfigExd CANFdConfigExd { get; set; }
/// <summary>
/// ///////////////////////////////////////////导航属性 CAN 一对一///////////////////////////////////////////////////////
/// </summary>
@@ -57,12 +71,12 @@ namespace CapMachine.Model.CANLIN
public CANConfigExd CANConfigExd { get; set; }
/// <summary>
/// ///////////////////////////////////////////导航属性 LIN 一对一///////////////////////////////////////////////////////
/// </summary>
public long LINConfigExdId { get; set; } // 外键字段,必要
public LINConfigExd LINConfigExd { get; set; }
}
}

View File

@@ -0,0 +1,53 @@
using FreeSql.DataAnnotations;
namespace CapMachine.Model.CANLIN
{
/// <summary>
/// 调度表的配置
/// 其实这些调度表是在DBC中有的但是图莫斯的驱动没有读取到这些信息
/// 那么我们在系统层面进行操作和保存这些信息
/// </summary>
[Table(Name = "LINScheduleConfig")]
public class LINScheduleConfig
{
/// <summary>
/// 主键
/// </summary>
[Column(IsPrimary = true, IsIdentity = true)]
public long Id { get; set; }
/// <summary>
/// 消息名称
/// </summary>
[Column(Name = "MsgName")]
public string? MsgName { get; set; }
/// <summary>
/// 消息的周期
/// </summary>
[Column(Name = "Cycle")]
public int Cycle { get; set; }
/// <summary>
/// 调度表的Index
/// LDF中可能有多个调度器
/// </summary>
[Column(Name = "SchTabIndex")]
public int SchTabIndex { get; set; }
/// <summary>
/// 调度表的名称
/// LDF中可能有多个调度器名称
/// </summary>
[Column(Name = "SchTabName")]
public int SchTabName { get; set; }
/// <summary>
/// ///////////////////////////////////////////导航属性///////////////////////////////////////////////////////
/// </summary>
public long CanLinConfigProId { get; set; }
public CanLinConfigPro? CanLinConfigPro { get; set; }
}
}

View File

@@ -1,6 +1,11 @@
using CapMachine.Wpf.Models.Tag;
using CapMachine.Core;
using CapMachine.Model.CANLIN;
using CapMachine.Wpf.Dtos;
using CapMachine.Wpf.Models.Tag;
using CapMachine.Wpf.Services;
using HslCommunication;
using ImTools;
using NLog;
using NPOI.OpenXmlFormats.Wordprocessing;
using Prism.Ioc;
using Prism.Mvvm;
@@ -33,6 +38,7 @@ namespace CapMachine.Wpf.CanDrive
{
ContainerProvider = containerProvider;
HighSpeedDataService = ContainerProvider.Resolve<HighSpeedDataService>();
LoggerService = ContainerProvider.Resolve<ILogService>();
//Stopwatch.Frequency表示高精度计时器每秒的计数次数ticks/秒每毫秒的ticks数 = 每秒的ticks数 ÷ 1000
TicksPerMs = Stopwatch.Frequency / 1000.0;
@@ -57,6 +63,11 @@ namespace CapMachine.Wpf.CanDrive
/// </summary>
public HighSpeedDataService HighSpeedDataService { get; set; }
/// <summary>
/// Logger 实例
/// </summary>
public ILogService LoggerService { get; set; }
/// <summary>
/// 开始Dbc文件写入
/// </summary>
@@ -123,6 +134,7 @@ namespace CapMachine.Wpf.CanDrive
///BufferSize 存储CAN消息缓冲区大小。
///返回值:
//大于等于0表示从CAN适配器内部成功读取到的CAN消息帧数若返回值小于0则说明调用该函数失败。
/// 目前是WriteCANIndex和ReadCANIndex需要相同
/// </summary>
public Byte WriteCANIndex { get; set; } = 0;
@@ -480,8 +492,13 @@ namespace CapMachine.Wpf.CanDrive
/// </summary>
private static Task CycleSendTask { get; set; }
/// <summary>
/// 定时扫描更新数据 扫描Task
/// </summary>
private static Task CycleUpdateCmdTask { get; set; }
StringBuilder ValueSb = new StringBuilder(16);
double[] ValueDouble=new double[5];
double[] ValueDouble = new double[5];
private bool _IsSendOk;
/// <summary>
@@ -497,6 +514,24 @@ namespace CapMachine.Wpf.CanDrive
RaisePropertyChanged();
_IsSendOk = value;
}
//RaisePropertyChanged();
}
}
private bool _IsReviceOk;
/// <summary>
/// 接收报文是否OK
/// </summary>
public bool IsReviceOk
{
get { return _IsReviceOk; }
set
{
if (_IsReviceOk != value)
{
RaisePropertyChanged();
_IsReviceOk = value;
}
}
}
@@ -652,6 +687,7 @@ namespace CapMachine.Wpf.CanDrive
// 严重延迟,重新校准
NextExecutionTime = Stopwatcher.ElapsedTicks;
Console.WriteLine("定时发送延迟过大,重新校准时间");
LoggerService.Info($"定时发送延迟过大,重新校准时间");
}
// 使用Stopwatch记录实际的执行间隔而不是DateTime
@@ -710,32 +746,43 @@ namespace CapMachine.Wpf.CanDrive
}
catch (TaskCanceledException)
{
LoggerService.Info($"精确周期发送CAN数据-任务被取消,正常退出");
// 任务被取消,正常退出
IsSendOk = false;
break;
}
catch (Exception ex)
{
Console.WriteLine($"CAN周期发送异常: {ex.Message}");
// 短暂暂停避免异常情况下CPU占用过高
IsSendOk = false;
await Task.Delay(10, token);
LoggerService.Info($"精确周期发送CAN数据-{ex.Message}");
}
}
IsSendOk = false;
}
catch (Exception ex)
{
// 确保在任何情况下(正常退出、异常、取消)都会停止计时器
Stopwatcher.Stop();
LoggerService.Info($"精确周期发送CAN数据-{ex.Message}");
// 清理其他可能的资源
Console.WriteLine("CAN周期发送任务已结束资源已清理");
IsSendOk = false;
}
finally
{
// 确保在任何情况下(正常退出、异常、取消)都会停止计时器
Stopwatcher.Stop();
LoggerService.Info("精确周期发送CAN数据-正常退出、异常、取消)都会停止计时器");
IsSendOk = false;
}
}, token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
@@ -750,6 +797,348 @@ namespace CapMachine.Wpf.CanDrive
#endregion
#region
private bool _SchEnable;
/// <summary>
/// 调度表使能
/// </summary>
public bool SchEnable
{
get { return _SchEnable; }
set
{
_SchEnable = value;
RaisePropertyChanged();
}
}
/// <summary>
/// 调度表的发送的报文数据
/// </summary>
private USB2CAN.CAN_MSG[] SchCanMsg { get; set; }
/// <summary>
/// 依据消息的分组
/// </summary>
private IEnumerable<IGrouping<string, CanCmdData>> GroupMsg { get; set; }
/// <summary>
/// 调度表集合数据
/// 总共3个调度表第一个表里面包含3帧数据第二个调度表包含6帧数据第三个调度表包含11帧数据
/// Byte[] MsgTabNum = new Byte[3] { 3, 6, 11 };
/// </summary>
private Byte[] MsgTabNum { get; set; }
/// <summary>
/// 调度表发送的次数集合
/// 第一个调度表循环发送数据第二个调度表循环发送数据第三个调度表只发送3次
/// UInt16[] SendTimes = new UInt16[3] { 0xFFFF, 0xFFFF, 3 };
/// </summary>
private UInt16[] SendTimes { get; set; }
/// <summary>
/// 预设的调度表的个数 常值
/// </summary>
private const int MsgTabCount = 5;
/// <summary>
/// 定时更新时间
/// </summary>
private int UpdateCycle = 100;
/// <summary>
/// CNA 调度表的配置信息
/// </summary>
public List<CANScheduleConfigDto> ListCANScheduleConfig { get; set; }
Random random = new Random();
/// <summary>
/// 更新数据 测试用废弃了
/// </summary>
public void UpdateValue()
{
//通过DBC进行对消息赋值
IntPtr msgPtSend = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CAN.CAN_MSG)));
int Index = 0;
//循环给MSG赋值数据
foreach (var itemMsg in GroupMsg)
{
foreach (var itemSignal in itemMsg)
{
itemSignal.SignalCmdValue = random.Next(0, 100);
CAN_DBCParser.DBC_SetSignalValue(DBCHandle, new StringBuilder(itemMsg.Key), new StringBuilder(itemSignal.SignalName), itemSignal.SignalCmdValue);
}
CAN_DBCParser.DBC_SyncValueToCANMsg(DBCHandle, new StringBuilder(itemMsg.Key), msgPtSend);
SchCanMsg[Index] = (USB2CAN.CAN_MSG)Marshal.PtrToStructure(msgPtSend, typeof(USB2CAN.CAN_MSG));
Index++;
}
//通过DBC写入数据后生成CanMsg
//将信号值填入CAN消息里面
//释放申请的临时缓冲区
Marshal.FreeHGlobal(msgPtSend);
////总共3个调度表第一个表里面包含3帧数据第二个调度表包含6帧数据第三个调度表包含11帧数据
//MsgTabNum = new Byte[1] { 1 };
////第一个调度表循环发送数据第二个调度表循环发送数据第三个调度表只发送3次
//SendTimes = new UInt16[1] { 0xFFFF };
//var ret = USB2CAN.CAN_SetSchedule(DevHandle, WriteCANIndex, SchCanMsg, MsgTabNum, SendTimes, 1);//配置调度表,该函数耗时可能会比较长,但是只需要执行一次即可
var ret = USB2CAN.CAN_UpdateSchedule(DevHandle, WriteCANIndex, 0, 0, SchCanMsg, 1);//配置调度表,该函数耗时可能会比较长,但是只需要执行一次即可
if (ret == USB2CAN.CAN_SUCCESS)
{
Console.WriteLine("Update CAN Schedule Success");
}
else
{
Console.WriteLine("Update CAN Schedule Error ret = {0}", ret);
return;
}
}
/// <summary>
/// 开始调度表执行
/// </summary>
public void StartSchedule()
{
if (CmdData.Count() == 0) return;
//依据报文进行分组
GroupMsg = CmdData.GroupBy(x => x.MsgName)!;
//初始化调度表要发送的消息结构
SchCanMsg = new USB2CAN.CAN_MSG[GroupMsg.Count()];
for (int i = 0; i < GroupMsg.Count(); i++)
{
SchCanMsg[i] = new USB2CAN.CAN_MSG();
SchCanMsg[i].Data = new Byte[64];
}
//通过DBC进行对消息赋值
IntPtr msgPtSend = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CAN.CAN_MSG)));
int Index = 0;
//循环给MSG赋值数据
foreach (var itemMsg in GroupMsg)
{
foreach (var itemSignal in itemMsg)
{
CAN_DBCParser.DBC_SetSignalValue(DBCHandle, new StringBuilder(itemMsg.Key), new StringBuilder(itemSignal.SignalName), itemSignal.SignalCmdValue);
}
CAN_DBCParser.DBC_SyncValueToCANMsg(DBCHandle, new StringBuilder(itemMsg.Key), msgPtSend);
//每个分组就是一个帧指令/消息数据
SchCanMsg[Index] = (USB2CAN.CAN_MSG)Marshal.PtrToStructure(msgPtSend, typeof(USB2CAN.CAN_MSG));
//分配当前消息帧在集合中的位置信息到ListCANScheduleConfig中方便实时更新时定位帧的位置
if (ListCANScheduleConfig.Any(a => a.MsgName == itemMsg.Key))
{
//把帧的位置给ListCANScheduleConfig方便更新时定位数据
ListCANScheduleConfig.FindFirst(a => a.MsgName == itemMsg.Key).MsgIndex = Index;
//设置当前这个报文的在调度表中的发送周期
SchCanMsg[Index].TimeStamp = (uint)ListCANScheduleConfig.FindFirst(a => a.MsgName == itemMsg.Key).Cycle;
}
Index++;
}
//通过DBC写入数据后生成CanMsg
//将信号值填入CAN消息里面
//释放申请的临时缓冲区
Marshal.FreeHGlobal(msgPtSend);
//********就是可以设置多个调度表放那里,但是运行时同一个时刻只能运行调度表其中的一个 ********
//****** 控制报文SchCanMsg和调度器中第一个调度器中的报文集合和要更新的报文集合都是同一个变量SchCanMsg ********
// *** SchCanMsg的Index序号和ListCANScheduleConfig的MsgIndex是一样的 ***
//图莫斯的Sample总共3个调度表第一个表里面包含3帧数据第二个调度表包含6帧数据第三个调度表包含11帧数据
//预设5个调度表但是我们只用其中第一个调度表第一个调度表中包括多少消息帧由系统的控制指令的帧的分布决定SchCanMsg.Count()是所需要的控制发送的帧,都放到第一个调度表中
MsgTabNum = new Byte[MsgTabCount] { (byte)SchCanMsg.Count(), 1, 1, 1, 1 };
//0xFFFF调度表循环发送数据X调度表循环发送的次数
//设置每个调度表的发送方式,约定全部为循环发送
SendTimes = new UInt16[MsgTabCount] { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF };
//SchCanMsg:需要发送的消息集合MsgTabNum调度表集合数据SendTimes发送次数集合数据调度表个数MsgTabCount
var ret = USB2CAN.CAN_SetSchedule(DevHandle, WriteCANIndex, SchCanMsg, MsgTabNum, SendTimes, MsgTabCount);//配置调度表,该函数耗时可能会比较长,但是只需要执行一次即可
if (ret == USB2CAN.CAN_SUCCESS)
{
Console.WriteLine("Set CAN Schedule Success");
}
else
{
Console.WriteLine("Set CAN Schedule Error ret = {0}", ret);
LoggerService.Info($"Set CAN Schedule Error; 返回错误代码:{ret}");
return;
}
//约定使用Index=0 1号调度器因为同一个时刻只能有一个调度器工作把所有的报文都要放到这个调度器中
//CAN_MSG的TimeStamp就是这个报文发送的周期由调度器协调
ret = USB2CAN.CAN_StartSchedule(DevHandle, WriteCANIndex, (byte)0, (byte)100, (byte)ListCANScheduleConfig.FirstOrDefault()!.OrderSend);
if (ret == USB2CAN.CAN_SUCCESS)
{
Console.WriteLine($"Start CAN Schedule 1 SuccessSchTabIndex{(byte)0} - Cycle{(byte)100} - OrderSend{(byte)1}");
}
else
{
Console.WriteLine("Start CAN Schedule 1 Error ret = {0}", ret);
LoggerService.Info($"Start CAN Schedule 1 Error;");
return;
}
//foreach (var itemGroupMsg in GroupMsg)
//{
// if (itemGroupMsg == null) continue;
// if (ListCANScheduleConfig.Any(a => a.MsgName!.Contains(itemGroupMsg.Key)))
// {
// var CANScheduleConfig = ListCANScheduleConfig.FindFirst(a => a.MsgName!.Contains(itemGroupMsg.Key));
// //配置表里面包括这个报文消息内容
// ret = USB2CAN.CAN_StartSchedule(DevHandle, WriteCANIndex, (byte)CANScheduleConfig.SchTabIndex, (byte)CANScheduleConfig.Cycle, (byte)CANScheduleConfig.OrderSend);
// if (ret == USB2CAN.CAN_SUCCESS)
// {
// Console.WriteLine($"Start CAN Schedule 1 SuccessSchTabIndex{(byte)CANScheduleConfig.SchTabIndex} - Cycle{(byte)CANScheduleConfig.Cycle} - OrderSend{(byte)CANScheduleConfig.OrderSend}");
// }
// else
// {
// Console.WriteLine("Start CAN Schedule 1 Error ret = {0}", ret);
// LoggerService.Info($"Start CAN Schedule 1 Error;消息名称:{CANScheduleConfig.MsgName}");
// return;
// }
// }
// else
// {
// LoggerService.Info($"调度表配置未发现对应的消息报文信息;报文信息{itemGroupMsg.Key}");
// }
//}
//走到这里说明调度表执行的是OK的
//IsSendOk = true;
}
/// <summary>
/// 停止调度表
/// </summary>
public void StopSchedule()
{
ret = USB2CAN.CAN_StopSchedule(DevHandle, WriteCANIndex);//启动第一个调度表,表里面的CAN帧并行发送
if (ret == USB2CAN.CAN_SUCCESS)
{
IsSendOk = false;
Console.WriteLine("Stop CAN Schedule");
LoggerService.Info($"Stop CAN Schedule");
}
else
{
Console.WriteLine("Start CAN Schedule Error ret = {0}", ret);
LoggerService.Info($"Stop CAN Schedule");
return;
}
}
/// <summary>
/// 循环使用的
/// </summary>
private int CycleUpdateIndex = 0;
/// <summary>
/// 循环更新调度表的指令数据
/// 定时更新数据到调度表中
/// </summary>
public void StartCycleUpdateCmd()
{
CycleUpdateCmdTask = Task.Run(async () =>
{
while (IsCycleSend)
{
await Task.Delay(UpdateCycle);
try
{
//通过DBC进行对消息赋值
IntPtr msgPtSend = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CAN.CAN_MSG)));
CycleUpdateIndex = 0;
//循环给MSG赋值数据顺序是固定的跟初始时设置是一样的
foreach (var itemMsg in GroupMsg)
{
foreach (var itemSignal in itemMsg)
{
//itemSignal.SignalCmdValue = random.Next(0, 100); //仿真测试数据使用
CAN_DBCParser.DBC_SetSignalValue(DBCHandle, new StringBuilder(itemMsg.Key), new StringBuilder(itemSignal.SignalName), itemSignal.SignalCmdValue);
}
CAN_DBCParser.DBC_SyncValueToCANMsg(DBCHandle, new StringBuilder(itemMsg.Key), msgPtSend);
SchCanMsg[CycleUpdateIndex] = (USB2CAN.CAN_MSG)Marshal.PtrToStructure(msgPtSend, typeof(USB2CAN.CAN_MSG));
CycleUpdateIndex++;
}
//通过DBC写入数据后生成CanMsg
//将信号值填入CAN消息里面
//释放申请的临时缓冲区
Marshal.FreeHGlobal(msgPtSend);
//CAN_UpdateSchedule 官网解释
// ---MsgTabIndex CAN调度表索引号
// ---MsgIndex 开始更新帧起始索引,若起始索引大于调度表帧数,则将帧添加到调度表后面
// ---pCanMsg 需要更新的CAN帧指针
// ---MsgNum pCanMsgTab里面包含的有效帧数
//CAN_UpdateSchedule中的MsgIndex表示当前的调度器中的帧Index序号
//因为调度表中的帧集合和控制帧的集合和要更新的帧集合都是同一个集合SchCanMsg
//默认1号调度表一个更新所有的帧数据
var ret = USB2CAN.CAN_UpdateSchedule(DevHandle, WriteCANIndex, (byte)0, (byte)(0), SchCanMsg, (byte)SchCanMsg.Count());//配置调度表,该函数耗时可能会比较长,但是只需要执行一次即可
if (ret == USB2CAN.CAN_SUCCESS)
{
IsSendOk = true;
Console.WriteLine($"Update CAN Schedule Success -- SchTabIndex{(byte)0} -- MsgIndex{(byte)(0)} ");
}
else
{
IsSendOk = false;
Console.WriteLine($"Update CAN Schedule Error ret = {ret} -- SchTabIndex{(byte)0} -- MsgIndex{(byte)(0)}");
//return;
}
//一个报文帧一个报文帧进行更新数据
////配置信息 默认启用1号调度器,MsgTabIndex=0
//foreach (var itemMsgSchConfig in ListCANScheduleConfig)
//{
// //USB2CAN.CAN_MSG[] SchCanMsg1=new CAN_MSG[1];
// //SchCanMsg1[0] = SchCanMsg[itemMsgSchConfig.MsgIndex];
// // MsgTabIndex CAN调度表索引号 ;MsgIndex 开始更新帧起始索引,若起始索引大于调度表帧数,则将帧添加到调度表后面, ;
// // pCanMsg 需要更新的CAN帧指针,消息数据 ; MsgNum pCanMsgTab里面包含的有效帧数一个调度表对应一个帧/消息即为1 (byte)(itemMsgSchConfig.MsgIndex+0)
// var ret = USB2CAN.CAN_UpdateSchedule(DevHandle, WriteCANIndex, (byte)0, (byte)(itemMsgSchConfig.MsgIndex), SchCanMsg, 1);//配置调度表,该函数耗时可能会比较长,但是只需要执行一次即可
// if (ret == USB2CAN.CAN_SUCCESS)
// {
// Console.WriteLine($"Update CAN Schedule Success -- SchTabIndex{(byte)itemMsgSchConfig.SchTabIndex} -- MsgIndex{(byte)(itemMsgSchConfig.MsgIndex)} ");
// }
// else
// {
// Console.WriteLine($"Update CAN Schedule Error ret = {ret} -- SchTabIndex{(byte)itemMsgSchConfig.SchTabIndex} -- MsgIndex{(byte)(itemMsgSchConfig.MsgIndex)}");
// //return;
// }
//}
}
catch (Exception ex)
{
IsSendOk = false;
LoggerService.Info($"时间:{DateTime.Now.ToString()}-【MSG】-{ex.Message}");
}
}
IsSendOk = false;
});
}
#endregion
/// <summary>
/// 循环获取CAN消息
@@ -764,12 +1153,14 @@ namespace CapMachine.Wpf.CanDrive
try
{
//另外一个CAN通道读取数据
USB2CAN.CAN_MSG[] CanMsgBuffer = new USB2CAN.CAN_MSG[128];
USB2CAN.CAN_MSG[] CanMsgBuffer = new USB2CAN.CAN_MSG[1024];
//申请数据缓冲区
IntPtr msgPtRead = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CAN.CAN_MSG)) * CanMsgBuffer.Length);
int CanNum = USB2CAN.CAN_GetMsgWithSize(DevHandle, ReadCANIndex, msgPtRead, CanMsgBuffer.Length);
//int CanNum = USB2CAN.CAN_GetMsgWithSize(DevHandle, 1, msgPtRead, CanMsgBuffer.Length);//测试用CAN卡 CAN1和CAN2 短接时测试用
if (CanNum > 0)
{
IsReviceOk = true;
Console.WriteLine("Read CanMsgNum = {0}", CanNum);
for (int i = 0; i < CanNum; i++)
{
@@ -797,13 +1188,15 @@ namespace CapMachine.Wpf.CanDrive
}
else if (CanNum == 0)
{
IsReviceOk = false;
Console.WriteLine("No CAN data!");
}
else
{
IsReviceOk = false;
Console.WriteLine("Get CAN data error!");
}
Console.WriteLine("");
//Console.WriteLine("");
//将CAN消息数据填充到信号里面用DBC解析数据
CAN_DBCParser.DBC_SyncCANMsgToValue(DBCHandle, msgPtRead, CanNum);
@@ -838,9 +1231,15 @@ namespace CapMachine.Wpf.CanDrive
}
catch (Exception ex)
{
//LogService.Info($"时间:{DateTime.Now.ToString()}-【Meter】-{ex.Message}");
IsReviceOk = false;
LoggerService.Info("接收出现异常");
}
//finally
//{
// IsReviceOk = false;
//}
}
IsReviceOk = false;
});
}
@@ -903,6 +1302,10 @@ namespace CapMachine.Wpf.CanDrive
DbcParserState = false;
IsCycleRevice = false;
IsCycleSend = false;
if (SchEnable)
{
StopSchedule();
}
}
}

View File

@@ -101,14 +101,22 @@ namespace CapMachine.Wpf.CanDrive
[DllImport("USB2XXX.dll")]
public static extern Int32 CAN_Init(Int32 DevHandle, Byte CANIndex, ref CAN_INIT_CONFIG pCanConfig);
[DllImport("USB2XXX.dll")]
public static extern Int32 CAN_Init2(Int32 DevHandle, Byte CANIndex, Int32 BaudRateBps, Byte EnResistor);
[DllImport("USB2XXX.dll")]
public static extern Int32 CAN_Filter_Init(Int32 DevHandle, Byte CANIndex, ref CAN_FILTER_CONFIG pFilterConfig);
[DllImport("USB2XXX.dll")]
public static extern Int32 CAN_FilterList_Init(Int32 DevHandle, Byte CANIndex, UInt32[] pIDList, Byte IDListLen);
[DllImport("USB2XXX.dll")]
public static extern Int32 CAN_StartGetMsg(Int32 DevHandle, Byte CANIndex);
[DllImport("USB2XXX.dll")]
public static extern Int32 CAN_StopGetMsg(Int32 DevHandle, Byte CANIndex);
[DllImport("USB2XXX.dll")]
public static extern Int32 CAN_SendMsg(Int32 DevHandle, Byte CANIndex, CAN_MSG[] pCanSendMsg, UInt32 SendMsgNum);
[DllImport("USB2XXX.dll")]
public static extern Int32 CAN_SendMsgSynch(Int32 DevHandle, Byte CANIndex, CAN_MSG[] pCanSendMsg, UInt32 SendMsgNum);
[DllImport("USB2XXX.dll")]
public static extern Int32 CAN_SendMsgWithTime(Int32 DevHandle, Byte CANIndex, CAN_MSG[] pCanSendMsg, UInt32 SendMsgNum);
[DllImport("USB2XXX.dll")]
public static extern Int32 CAN_GetMsg(Int32 DevHandle, Byte CANIndex, IntPtr pCanGetMsg);
[DllImport("USB2XXX.dll")]
public static extern Int32 CAN_GetMsgWithSize(Int32 DevHandle, Byte CANIndex, IntPtr pCanGetMsg, Int32 BufferSize);
@@ -121,9 +129,17 @@ namespace CapMachine.Wpf.CanDrive
[DllImport("USB2XXX.dll")]
public static extern Int32 CAN_StartSchedule(Int32 DevHandle, Byte CANIndex, Byte MsgTabIndex, Byte TimePrecMs, Byte OrderSend);
[DllImport("USB2XXX.dll")]
public static extern Int32 CAN_UpdateSchedule(Int32 DevHandle, Byte CANIndex, Byte MsgTabIndex, Byte MsgIndex, CAN_MSG[] pCanMsg, Byte MsgNum);
[DllImport("USB2XXX.dll")]
public static extern Int32 CAN_StopSchedule(Int32 DevHandle, Byte CANIndex);
[DllImport("USB2XXX.dll")]
public static extern Int32 CAN_SetRelay(Int32 DevHandle, Byte RelayState);
[DllImport("USB2XXX.dll")]
public static extern Int32 CAN_Stop(Int32 DevHandle, Byte CANIndex);
[DllImport("USB2XXX.dll")]
public static extern Int64 CAN_GetStartTime(Int32 DevHandle, Byte CANIndex);
[DllImport("USB2XXX.dll")]
public static extern Int32 CAN_ResetStartTime(Int32 DevHandle, Byte CANIndex);
//CAN Bootloader相关函数
[DllImport("USB2XXX.dll")]

View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace CapMachine.Wpf.Dtos
{
public class CANConfigExdDto:BindableBase
public class CANConfigExdDto : BindableBase
{
/// <summary>
/// 主键
@@ -43,5 +43,15 @@ namespace CapMachine.Wpf.Dtos
get { return _DbcPath; }
set { _DbcPath = value; RaisePropertyChanged(); }
}
private bool _SchEnable;
/// <summary>
/// 调度表是否启用
/// </summary>
public bool SchEnable
{
get { return _SchEnable; }
set { _SchEnable = value; RaisePropertyChanged(); }
}
}
}

View File

@@ -0,0 +1,83 @@
using CapMachine.Model.CANLIN;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CapMachine.Wpf.Dtos
{
/// <summary>
/// CANScheduleConfigDto
/// </summary>
public class CANScheduleConfigDto : BindableBase
{
/// <summary>
/// 主键
/// </summary>
public long Id { get; set; }
private string? _MsgName;
/// <summary>
/// 消息名称/帧名称
/// </summary>
public string? MsgName
{
get { return _MsgName; }
set { _MsgName = value; RaisePropertyChanged(); }
}
private int _Cycle;
/// <summary>
/// 周期
/// </summary>
public int Cycle
{
get { return _Cycle; }
set { _Cycle = value; RaisePropertyChanged(); }
}
private int _OrderSend;
/// <summary>
/// 发送方式
/// </summary>
public int OrderSend
{
get { return _OrderSend; }
set { _OrderSend = value; RaisePropertyChanged(); }
}
private int _SchTabIndex;
/// <summary>
/// 调度表的Index序列
/// </summary>
public int SchTabIndex
{
get { return _SchTabIndex; }
set { _SchTabIndex = value; RaisePropertyChanged(); }
}
/// <summary>
/// 在更新调度表数据时,我们有一个整体的帧数据指令集合,但是这些帧数据集合,分属于不同的调度表,
/// 这个在开始时生成整体的帧数据指令集合才会把这个MsgIndex分配上这个不需要保存到数据库中对接使用
/// </summary>
public int MsgIndex { get; set; }
/// <summary>
/// 程序的ID
/// </summary>
public long CanLinConfigProId { get; set; }
private CanLinConfigPro _CanLinConfigPro;
/// <summary>
/// 所属的程序
/// </summary>
public CanLinConfigPro CanLinConfigPro
{
get { return _CanLinConfigPro; }
set { _CanLinConfigPro = value; RaisePropertyChanged(); }
}
}
}

View File

@@ -0,0 +1,14 @@
using AutoMapper;
using CapMachine.Model.CANLIN;
using CapMachine.Wpf.Dtos;
namespace CapMachine.Wpf.MapperProfile
{
public class CANScheduleConfigProfile : Profile
{
public CANScheduleConfigProfile()
{
CreateMap<CANScheduleConfig, CANScheduleConfigDto>().ReverseMap();
}
}
}

View File

@@ -1,5 +1,6 @@
using CapMachine.Model.CANLIN;
using CapMachine.Wpf.CanDrive;
using CapMachine.Wpf.Dtos;
using ImTools;
using Prism.Ioc;
using Prism.Mvvm;
@@ -20,15 +21,17 @@ namespace CapMachine.Wpf.Services
{
public HighSpeedDataService HighSpeedDataService { get; }
public LogicRuleService LogicRuleService { get; }
/// <summary>
/// 实例化函数
/// </summary>
public CanDriveService(HighSpeedDataService highSpeedDataService, IContainerProvider containerProvider)
public CanDriveService(HighSpeedDataService highSpeedDataService, IContainerProvider containerProvider, LogicRuleService logicRuleService)
{
ToomossCanDrive = new ToomossCan(containerProvider);
//高速数据服务
HighSpeedDataService = highSpeedDataService;
LogicRuleService = logicRuleService;
//ToomossCanDrive.StartCanDrive();
}
@@ -124,6 +127,11 @@ namespace CapMachine.Wpf.Services
/// </summary>
public List<CanCmdData> CmdData { get; set; } = new List<CanCmdData>();
/// <summary>
/// CNA 调度表的配置信息
/// </summary>
public List<CANScheduleConfigDto> ListCANScheduleConfig { get; set; }
/// <summary>
/// 增加发送的指令数据
/// </summary>
@@ -172,14 +180,26 @@ namespace CapMachine.Wpf.Services
/// <param name="canCmdData"></param>
public void UpdateSpeedCmdData(double SpeedData)
{
//if (SpeedCanCmdData != null)
//{
// SpeedCanCmdData.SignalCmdValue = SpeedData;
//}
if (SpeedCanCmdData != null)
{
SpeedCanCmdData.SignalCmdValue = SpeedData;
//首先是否判断是有斜率
if (SpeedCanCmdData.LogicRuleDto == null)
{
//没有启动逻辑规则处理
SpeedCanCmdData.SignalCmdValue = SpeedData;
}
else
{
//LogicRuleService.ApplyExpressionFast(SpeedData, SpeedCanCmdData.LogicRuleDto);
SpeedCanCmdData.SignalCmdValue = LogicRuleService.ApplyExpressionFast(SpeedData, SpeedCanCmdData.LogicRuleDto);
//Console.WriteLine($"实时转换后转速值:{SpeedCanCmdData.SignalCmdValue}-SV值:{SpeedData}");
}
}
//if (EnableCanCmdData != null)
//{
// EnableCanCmdData.SignalCmdValue = 1;
//}
}
/// <summary>
@@ -293,10 +313,39 @@ namespace CapMachine.Wpf.Services
{
if (CmdData.Count > 0)
{
ToomossCanDrive.IsCycleSend = true;
ToomossCanDrive.CmdData = CmdData;
//ToomossCanDrive.StartCycleSendMsg();
ToomossCanDrive.StartPrecisionCycleSendMsg();
if (ToomossCanDrive.SchEnable)
{
//使用调度表的话,需要在调度表中配置信息后才可以进行操作
var GroupMsg = ToomossCanDrive.CmdData.GroupBy(a => a.MsgName).ToList();
foreach (var itemMsg in GroupMsg)
{
if (!ListCANScheduleConfig.ToList().Any(a => a.MsgName == itemMsg.Key))
{
System.Windows.MessageBox.Show($"你使能了调度表,但是调度表中没有设置【{itemMsg.Key}】信息,请设置后再操作", "提示", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Hand);
return;
}
}
if (ListCANScheduleConfig == null && ListCANScheduleConfig!.Count() == 0)
{
System.Windows.MessageBox.Show("调度表配置为空数据,请检查!将无法发送数据", "提示", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Hand);
return;
}
ToomossCanDrive.ListCANScheduleConfig = ListCANScheduleConfig!;
ToomossCanDrive.StartSchedule();
ToomossCanDrive.StartCycleUpdateCmd();
}
else
{
ToomossCanDrive.StartPrecisionCycleSendMsg();
//ToomossCanDrive.StartCycleSendMsg();
}
ToomossCanDrive.IsCycleSend = true;
}
else
{
@@ -305,7 +354,15 @@ namespace CapMachine.Wpf.Services
}
else
{
ToomossCanDrive.IsCycleSend = false;
if (ToomossCanDrive.SchEnable)
{
ToomossCanDrive.IsCycleSend = false;
ToomossCanDrive.StopSchedule();
}
else
{
ToomossCanDrive.IsCycleSend = false;
}
}
}
@@ -374,6 +431,7 @@ namespace CapMachine.Wpf.Services
//double.TryParse(ListCanDbcModel.FindFirst(a => a.Name == Name).SignalRtValue, out double Result1);
//return double.TryParse(ListCanDbcModel.FindFirst(a => a.Name == Name).SignalRtValue.Split(" ")[0], out double Result) == true ? Result : 0;
return double.TryParse(ListCanDbcModel.FindFirst(a => a.Name == Name).SignalRtValue.Split(" ")[0], out double Result) == true ? Result : 0;
}
return 0;
}

View File

@@ -37,7 +37,7 @@ namespace CapMachine.Wpf.ViewModels
{
public CANConfigViewModel(IDialogService dialogService, IFreeSql freeSql,
IEventAggregator eventAggregator, IRegionManager regionManager, SysRunService sysRunService,
ComActionService actionService,
ComActionService actionService, LogicRuleService logicRuleService,
ConfigService configService, CanDriveService canDriveService,
IMapper mapper, MachineRtDataService machineRtDataService)
{
@@ -47,6 +47,7 @@ namespace CapMachine.Wpf.ViewModels
RegionManager = regionManager;
SysRunService = sysRunService;
ComActionService = actionService;
LogicRuleService = logicRuleService;
ConfigService = configService;
CanDriveService = canDriveService;
Mapper = mapper;
@@ -55,6 +56,31 @@ namespace CapMachine.Wpf.ViewModels
//MachineDataService = machineDataService;
DialogService = dialogService;
EventAggregator.GetEvent<LogicRuleChangeEvent>().Subscribe(LogicRuleChangeEventCall);
//数据波特率
DataBaudRateCbxItems = new ObservableCollection<CbxItems>()
{
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<CbxItems>()
{
new CbxItems(){ Key="转速",Text="转速"},
@@ -73,6 +99,7 @@ namespace CapMachine.Wpf.ViewModels
new CbxItems(){ Key="通讯Cmp转速",Text="通讯Cmp转速"},
new CbxItems(){ Key="通讯Cmp母线电压",Text="通讯Cmp母线电压"},
new CbxItems(){ Key="通讯Cmp母线电流",Text="通讯Cmp母线电流"},
new CbxItems(){ Key="通讯Cmp逆变器温度",Text="通讯Cmp逆变器温度"},
new CbxItems(){ Key="通讯Cmp相电流",Text="通讯Cmp相电流"},
new CbxItems(){ Key="通讯Cmp功率",Text="通讯Cmp功率"},
new CbxItems(){ Key="通讯Cmp芯片温度",Text="通讯Cmp芯片温度"},
@@ -85,7 +112,8 @@ namespace CapMachine.Wpf.ViewModels
new CbxItems(){ Key="通讯PTC模块温度",Text="通讯PTC模块温度"},
};
InitLoadCanConfigPro();
//初始化写规则下拉框
InitWriteRuleCbx();
}
@@ -94,6 +122,7 @@ namespace CapMachine.Wpf.ViewModels
/// </summary>
public IFreeSql FreeSql { get; }
public IEventAggregator EventAggregator { get; }
public LogicRuleService LogicRuleService { get; }
public IRegionManager RegionManager { get; }
public SysRunService SysRunService { get; }
public ComActionService ComActionService { get; }
@@ -108,6 +137,39 @@ namespace CapMachine.Wpf.ViewModels
public IDialogService DialogService { get; }
#region
/// <summary>
/// 逻辑更改事件
/// </summary>
/// <param name="msg"></param>
/// <exception cref="NotImplementedException"></exception>
private void LogicRuleChangeEventCall(string msg)
{
//InitWriteRuleCbx();
}
/// <summary>
/// 初始化写规则下拉框
/// </summary>
private void InitWriteRuleCbx()
{
WriteRuleCbxItems = new ObservableCollection<CbxItems>();
//选择的读写规则
foreach (var itemRule in LogicRuleService.LogicRuleDtos)
{
WriteRuleCbxItems.Add(new CbxItems()
{
Key = itemRule.Id.ToString(),
Text = itemRule.Name
});
}
}
#endregion
#region CanConfigPro
@@ -119,7 +181,8 @@ namespace CapMachine.Wpf.ViewModels
//CAN配置集合数据
canLinConfigPros = FreeSql.Select<CanLinConfigPro>().Where(a => a.CANLINInfo == CANLIN.CAN)
.Include(a => a.CANConfigExd)
.IncludeMany(a => a.CanLinConfigContents)
.IncludeMany(a => a.CanLinConfigContents, then => then.Include(b => b.LogicRule))//,then=> then.Include(b=>b.LogicRule) //.IncludeMany(a => a.CanLinConfigContents)
.IncludeMany(a => a.CanScheduleConfigs)//
.ToList();
ListCanLinConfigPro = new ObservableCollection<CanLinConfigPro>(canLinConfigPros);
@@ -128,7 +191,7 @@ namespace CapMachine.Wpf.ViewModels
SelectCanLinConfigPro = canLinConfigPros.Where(a => a.Id == SelectCanLinConfigPro.Id).FirstOrDefault()!;
//无数据就返回
if (SelectCanLinConfigPro == null) return;
SelectedCANConfigExdDto = Mapper.Map<CANConfigExdDto>(SelectCanLinConfigPro!.CANConfigExd);
//配置信息
@@ -147,6 +210,7 @@ namespace CapMachine.Wpf.ViewModels
MsgName = item.MsgFrameName,
SignalName = item.SignalName,
SignalCmdValue = double.TryParse(item.DefautValue, out double result) == true ? result : 0,
LogicRuleDto = Mapper.Map<LogicRuleDto>(item.LogicRule),
});
//CanDriveService.CmdData.Add(new CanCmdData()
//{
@@ -157,11 +221,26 @@ namespace CapMachine.Wpf.ViewModels
//});
}
}
else
{
ListWriteCanLinRWConfigDto = new ObservableCollection<CanLinRWConfigDto>();
}
var ReadData = SelectCanLinConfigPro.CanLinConfigContents!.Where(a => a.RWInfo == RW.Read).ToList();
if (ReadData != null && ReadData.Count > 0)
{
ListReadCanLinRWConfigDto = new ObservableCollection<CanLinRWConfigDto>(Mapper.Map<List<CanLinRWConfigDto>>(ReadData));
}
else
{
ListReadCanLinRWConfigDto = new ObservableCollection<CanLinRWConfigDto>();
}
//调度表配置信息
if (SelectCanLinConfigPro.CanScheduleConfigs != null && SelectCanLinConfigPro.CanScheduleConfigs.Count() > 0)
{
ListCANScheduleConfigDto = new ObservableCollection<CANScheduleConfigDto>(Mapper.Map<List<CANScheduleConfigDto>>(SelectCanLinConfigPro.CanScheduleConfigs));
}
//匹配选中的SelectCanLinConfigPro.CanLinConfigContents和ListCanDbcModel
MatchSeletedAndCanDbcModel();
@@ -500,6 +579,7 @@ namespace CapMachine.Wpf.ViewModels
MsgName = item.MsgFrameName,
SignalName = item.SignalName,
SignalCmdValue = double.TryParse(item.DefautValue, out double result) == true ? result : 0,
LogicRuleDto = Mapper.Map<LogicRuleDto>(item.LogicRule),
});
//CanDriveService.CmdData.Add(new CanCmdData()
@@ -512,14 +592,33 @@ namespace CapMachine.Wpf.ViewModels
}
}
else
{
ListWriteCanLinRWConfigDto = new ObservableCollection<CanLinRWConfigDto>();
}
var ReadData = SelectCanLinConfigPro.CanLinConfigContents!.Where(a => a.RWInfo == RW.Read).ToList();
if (ReadData != null && ReadData.Count > 0)
{
ListReadCanLinRWConfigDto = new ObservableCollection<CanLinRWConfigDto>(Mapper.Map<List<CanLinRWConfigDto>>(ReadData));
}
else
{
ListReadCanLinRWConfigDto = new ObservableCollection<CanLinRWConfigDto>();
}
SelectCanLinConfigProConfigName = SelectCanLinConfigPro.ConfigName;
//调度表配置信息
if (SelectCanLinConfigPro.CanScheduleConfigs != null && SelectCanLinConfigPro.CanScheduleConfigs.Count() > 0)
{
ListCANScheduleConfigDto = new ObservableCollection<CANScheduleConfigDto>(Mapper.Map<List<CANScheduleConfigDto>>(SelectCanLinConfigPro.CanScheduleConfigs));
}
else
{
ListCANScheduleConfigDto = new ObservableCollection<CANScheduleConfigDto>();
}
return;
}
//先判断是否是正确的集合数据防止DataGrid的数据源刷新导致的触发事件
@@ -707,7 +806,7 @@ namespace CapMachine.Wpf.ViewModels
}
//(par as SelectionChangedEventArgs)!.AddedItems[0] == null
if ((par as SelectionChangedEventArgs)!.AddedItems.Count==0)
if ((par as SelectionChangedEventArgs)!.AddedItems.Count == 0)
{
return;
}
@@ -802,6 +901,57 @@ namespace CapMachine.Wpf.ViewModels
set { _SelectedCANConfigExdDto = value; RaisePropertyChanged(); }
}
private ObservableCollection<CbxItems> _DataBaudRateCbxItems;
/// <summary>
/// CAN 数据波特率
/// </summary>
public ObservableCollection<CbxItems> DataBaudRateCbxItems
{
get { return _DataBaudRateCbxItems; }
set { _DataBaudRateCbxItems = value; RaisePropertyChanged(); }
}
private DelegateCommand<object> _SchEnableCmd;
/// <summary>
/// 调度表的使能 操作的指令
/// </summary>
public DelegateCommand<object> SchEnableCmd
{
set
{
_SchEnableCmd = value;
}
get
{
if (_SchEnableCmd == null)
{
_SchEnableCmd = new DelegateCommand<object>((Par) => SchEnableCmdCall(Par));
}
return _SchEnableCmd;
}
}
/// <summary>
/// 调度表的使能信息
/// </summary>
/// <param name="par"></param>
/// <exception cref="NotImplementedException"></exception>
private void SchEnableCmdCall(object par)
{
var dd = SelectedCANConfigExdDto.SchEnable;
var Result = (bool)par;
if (Result)
{
CanDriveService.ToomossCanDrive.SchEnable = true;
}
else
{
CanDriveService.ToomossCanDrive.SchEnable = false;
}
}
private DelegateCommand<string> _CanOpCmd;
/// <summary>
/// CAN操作的指令
@@ -845,7 +995,7 @@ namespace CapMachine.Wpf.ViewModels
//系统使用了CAN
ConfigService.CanLinRunStateModel.CurSysSelectedCanLin = CanLinEnum.Can;
}
//CAN DBC配置 有DBC配置的话则直接加载DBC信息
if (!string.IsNullOrEmpty(SelectCanLinConfigPro.CANConfigExd.DbcPath))
{
@@ -889,6 +1039,7 @@ namespace CapMachine.Wpf.ViewModels
.Set(a => a.DbcPath, SelectedCANConfigExdDto.DbcPath)
.Set(a => a.Cycle, SelectedCANConfigExdDto.Cycle)
.Set(a => a.BaudRate, SelectedCANConfigExdDto.BaudRate)
.Set(a => a.SchEnable, SelectedCANConfigExdDto.SchEnable)
.Where(a => a.Id == SelectedCANConfigExdDto.Id)
.ExecuteUpdated();
}
@@ -950,7 +1101,12 @@ namespace CapMachine.Wpf.ViewModels
break;
case "CycleSend"://循环发送你
//循环发送数据
//有可能加载完毕后不手动改变状态,导致值没有传输,所以这里赋值
CanDriveService.ToomossCanDrive.SchEnable = SelectedCANConfigExdDto.SchEnable;
//无论有没有调度表都要把这个配置给CanDriveService
CanDriveService.ListCANScheduleConfig = ListCANScheduleConfigDto.ToList();
CanDriveService.CycleSendMsg();
//Listen
@@ -992,6 +1148,16 @@ namespace CapMachine.Wpf.ViewModels
set { _WriteNameCbxItems = value; RaisePropertyChanged(); }
}
private ObservableCollection<CbxItems> _WriteRuleCbxItems;
/// <summary>
/// 写入的规格集合
/// </summary>
public ObservableCollection<CbxItems> WriteRuleCbxItems
{
get { return _WriteRuleCbxItems; }
set { _WriteRuleCbxItems = value; RaisePropertyChanged(); }
}
private ObservableCollection<CbxItems> _ReadNameCbxItems;
/// <summary>
@@ -1004,6 +1170,28 @@ namespace CapMachine.Wpf.ViewModels
}
private ObservableCollection<CbxItems> _ReadRuleCbxItems;
/// <summary>
/// 读取的规格集合
/// </summary>
public ObservableCollection<CbxItems> ReadRuleCbxItems
{
get { return _ReadRuleCbxItems; }
set { _ReadRuleCbxItems = value; RaisePropertyChanged(); }
}
private ObservableCollection<CANScheduleConfigDto> _ListCANScheduleConfigDto;
/// <summary>
///调度表集合
/// </summary>
public ObservableCollection<CANScheduleConfigDto> ListCANScheduleConfigDto
{
get { return _ListCANScheduleConfigDto; }
set { _ListCANScheduleConfigDto = value; RaisePropertyChanged(); }
}
//private string _SelectedWriteName;
///// <summary>
///// 选中的写入的Name
@@ -1118,6 +1306,7 @@ namespace CapMachine.Wpf.ViewModels
//直接修改
FreeSql.Update<CanLinRWConfig>(item.Id)
.Set(a => a.Name, item.Name)
.Set(a => a.LogicRuleId, item.LogicRuleId)
.Set(a => a.DefautValue, item.DefautValue)
.ExecuteAffrows();
//ListWriteCanLinRWConfigDto.Remove(SelectedWriteCanLinRWConfigDto);
@@ -1148,6 +1337,44 @@ namespace CapMachine.Wpf.ViewModels
System.Windows.MessageBox.Show("请选中后再进行【删除】操作?", "提示", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Hand);
}
break;
case "WriteSch"://调度表
var data = CanDriveService.CmdData.GroupBy(a => a.MsgName).Select(a => a.Key).ToList();
if (data != null && data.Count > 0)
{
//弹窗
DialogService.ShowDialog("DialogCANSchConfigView", new DialogParameters() {
{"ListMsg", CanDriveService.CmdData.GroupBy(a=>a.MsgName).Select(a=>a.Key).ToList() },
{ "ListCANScheduleConfigDto",ListCANScheduleConfigDto},
{ "SelectCanLinConfigProId",SelectCanLinConfigPro.Id},
}, (par) =>
{
if (par.Result == ButtonResult.OK)
{
////程序名称
ListCANScheduleConfigDto = par.Parameters.GetValue<ObservableCollection<CANScheduleConfigDto>>("ReturnValue");
//把更新后的最新值给当前的主集合中
SelectCanLinConfigPro.CanScheduleConfigs = Mapper.Map<List<CANScheduleConfig>>(ListCANScheduleConfigDto.ToList());
}
else if (par.Result == ButtonResult.Cancel)
{
//取消
}
});
}
else
{
System.Windows.MessageBox.Show("未发现写入的执行的命令数据,无法配置?", "提示", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Hand);
}
break;
default:
break;

View File

@@ -406,7 +406,14 @@
FontSize="18"
Text="&#xe9f8;" />
<TextBlock Style="{StaticResource TextBlockStyle}" Text="波特率" />
<TextBox Style="{StaticResource TextBoxStyle}" Text="{Binding SelectedCANConfigExdDto.BaudRate}" />
<ComboBox
Width="100"
DisplayMemberPath="Text"
FontSize="16"
ItemsSource="{Binding DataBaudRateCbxItems}"
SelectedValue="{Binding SelectedCANConfigExdDto.BaudRate, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedValuePath="Key" />
<!--<TextBox Style="{StaticResource TextBoxStyle}" Text="{Binding SelectedCANConfigExdDto.BaudRate}" />-->
</StackPanel>
<StackPanel Grid.Row="1" Orientation="Horizontal">
@@ -574,6 +581,87 @@
</StackPanel>
<StackPanel
Grid.Row="1"
Grid.Column="1"
Margin="-20,0"
Orientation="Horizontal">
<TextBlock
Margin="0,0,0,0"
VerticalAlignment="Center"
FontFamily="/Assets/Fonts/#iconfont"
FontSize="20"
Text="&#xe977;" />
<TextBlock
Width="80"
Style="{StaticResource TextBlockStyle}"
Text="报文状态:" />
<Border
Margin="0,12"
BorderThickness="1"
CornerRadius="5">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="Gray" />
<Style.Triggers>
<DataTrigger Binding="{Binding CanDriveService.ToomossCanDrive.IsSendOk}" Value="true">
<Setter Property="Background" Value="LimeGreen" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBlock
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="White"
Text="发送" />
</Border>
<Border
Margin="2,12"
BorderThickness="1"
CornerRadius="5">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="Gray" />
<Style.Triggers>
<DataTrigger Binding="{Binding CanDriveService.ToomossCanDrive.IsReviceOk}" Value="true">
<Setter Property="Background" Value="LimeGreen" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBlock
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="White"
Text="接收" />
</Border>
<TextBlock
Margin="5,0,0,0"
VerticalAlignment="Center"
FontFamily="/Assets/Fonts/#iconfont"
FontSize="20"
Text="&#xe796;" />
<TextBlock
Width="90"
Style="{StaticResource TextBlockStyle}"
Text="启用调度表:" />
<ToggleButton
Width="40"
Margin="5,2"
Command="{Binding SchEnableCmd}"
CommandParameter="{Binding SelectedCANConfigExdDto.SchEnable}"
IsChecked="{Binding SelectedCANConfigExdDto.SchEnable}"
Style="{StaticResource MaterialDesignSwitchToggleButton}"
ToolTip="启用调度表" />
</StackPanel>
</Grid>
</Grid>
@@ -632,6 +720,24 @@
Margin="0,0,15,0"
HorizontalAlignment="Right"
Orientation="Horizontal">
<Button
Margin="5,0"
Command="{Binding WriteCmd}"
CommandParameter="WriteSch"
Foreground="White">
<StackPanel Orientation="Horizontal">
<TextBlock
Margin="2,0"
VerticalAlignment="Center"
FontFamily="/Assets/Fonts/#iconfont"
FontSize="18"
Text="&#xe796;" />
<TextBlock
VerticalAlignment="Center"
FontSize="14"
Text="调度表" />
</StackPanel>
</Button>
<Button
Margin="5,0"
Command="{Binding WriteCmd}"
@@ -717,6 +823,21 @@
<TextBlock FontWeight="Bold" Text="默认值" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTemplateColumn Width="200" Header="规则名称">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox
DisplayMemberPath="Text"
ItemsSource="{Binding Source={StaticResource Proxy}, Path=Data.WriteRuleCbxItems}"
SelectedValue="{Binding LogicRuleId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedValuePath="Key" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">