其他程序的CAN CANFD LIN的移植
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -353,19 +365,19 @@ namespace CapMachine.Wpf.CanDrive
|
||||
{
|
||||
StringBuilder MsgName = new StringBuilder(32);
|
||||
CAN_DBCParser.DBC_GetMsgName(DBCHandle, i, MsgName);
|
||||
//Console.WriteLine("Msg.Name = {0}", MsgName);
|
||||
Console.WriteLine("Msg.Name = {0}", MsgName);
|
||||
int DBCSigNum = CAN_DBCParser.DBC_GetMsgSignalQuantity(DBCHandle, MsgName);
|
||||
StringBuilder Publisher = new StringBuilder(32);
|
||||
CAN_DBCParser.DBC_GetMsgPublisher(DBCHandle, MsgName, Publisher);
|
||||
long MsgId;
|
||||
MsgId = CAN_DBCParser.DBC_GetMsgIDByName(DBCHandle, MsgName);
|
||||
|
||||
//Console.Write("Signals:");
|
||||
Console.Write("Signals:");
|
||||
for (int j = 0; j < DBCSigNum; j++)
|
||||
{
|
||||
StringBuilder SigName = new StringBuilder(32);
|
||||
CAN_DBCParser.DBC_GetMsgSignalName(DBCHandle, MsgName, j, SigName);
|
||||
//Console.Write("{0} ", SigName);
|
||||
Console.Write("{0} ", SigName);
|
||||
|
||||
//增加信息数据
|
||||
ListCanDbcModel.Add(new CanDbcModel()
|
||||
@@ -379,7 +391,7 @@ namespace CapMachine.Wpf.CanDrive
|
||||
Publisher = Publisher.ToString()
|
||||
});
|
||||
}
|
||||
//Console.WriteLine("");
|
||||
Console.WriteLine("");
|
||||
}
|
||||
|
||||
//Dbc解析成功
|
||||
@@ -429,11 +441,11 @@ namespace CapMachine.Wpf.CanDrive
|
||||
int SendedNum = USB2CAN.CAN_SendMsg(DevHandle, WriteCANIndex, CanMsg, (uint)CanMsg.Length);
|
||||
if (SendedNum >= 0)
|
||||
{
|
||||
//Console.WriteLine("Success send frames:{0}", SendedNum);
|
||||
Console.WriteLine("Success send frames:{0}", SendedNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Console.WriteLine("Send CAN data failed! {0}", SendedNum);
|
||||
Console.WriteLine("Send CAN data failed! {0}", SendedNum);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -480,7 +492,48 @@ 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];
|
||||
|
||||
private bool _IsSendOk;
|
||||
/// <summary>
|
||||
/// 发送报文是否OK
|
||||
/// </summary>
|
||||
public bool IsSendOk
|
||||
{
|
||||
get { return _IsSendOk; }
|
||||
set
|
||||
{
|
||||
if (_IsSendOk != value)
|
||||
{
|
||||
RaisePropertyChanged();
|
||||
_IsSendOk = value;
|
||||
}
|
||||
//RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private bool _IsReviceOk;
|
||||
/// <summary>
|
||||
/// 接收报文是否OK
|
||||
/// </summary>
|
||||
public bool IsReviceOk
|
||||
{
|
||||
get { return _IsReviceOk; }
|
||||
set
|
||||
{
|
||||
if (_IsReviceOk != value)
|
||||
{
|
||||
RaisePropertyChanged();
|
||||
_IsReviceOk = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 要发送的数据
|
||||
@@ -530,11 +583,11 @@ namespace CapMachine.Wpf.CanDrive
|
||||
int SendedNum = USB2CAN.CAN_SendMsg(DevHandle, WriteCANIndex, CanMsg, (uint)CanMsg.Length);
|
||||
if (SendedNum >= 0)
|
||||
{
|
||||
//Console.WriteLine("Success send frames:{0}", SendedNum);
|
||||
Console.WriteLine("Success send frames:{0}", SendedNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Console.WriteLine("Send CAN data failed! {0}", SendedNum);
|
||||
Console.WriteLine("Send CAN data failed! {0}", SendedNum);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -546,97 +599,6 @@ namespace CapMachine.Wpf.CanDrive
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 循环获取CAN消息
|
||||
/// </summary>
|
||||
public void StartCycleReviceCanMsg()
|
||||
{
|
||||
CycleReviceTask = Task.Run(async () =>
|
||||
{
|
||||
while (IsCycleRevice)
|
||||
{
|
||||
await Task.Delay(ReviceCycle);
|
||||
try
|
||||
{
|
||||
//另外一个CAN通道读取数据
|
||||
USB2CAN.CAN_MSG[] CanMsgBuffer = new USB2CAN.CAN_MSG[128];
|
||||
//申请数据缓冲区
|
||||
IntPtr msgPtRead = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CAN.CAN_MSG)) * CanMsgBuffer.Length);
|
||||
int CanNum = USB2CAN.CAN_GetMsgWithSize(DevHandle, ReadCANIndex, msgPtRead, CanMsgBuffer.Length);
|
||||
if (CanNum > 0)
|
||||
{
|
||||
Console.WriteLine("Read CanMsgNum = {0}", CanNum);
|
||||
for (int i = 0; i < CanNum; i++)
|
||||
{
|
||||
//CanMsgBuffer[i] = (USB2CAN.CAN_MSG)Marshal.PtrToStructure((IntPtr)((UInt32)msgPtRead + i * Marshal.SizeOf(typeof(USB2CAN.CAN_MSG))), typeof(USB2CAN.CAN_MSG)); //有溢出报错
|
||||
CanMsgBuffer[i] = (USB2CAN.CAN_MSG)Marshal.PtrToStructure((IntPtr)(msgPtRead + i * Marshal.SizeOf(typeof(USB2CAN.CAN_MSG))), typeof(USB2CAN.CAN_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].DataLen; j++)
|
||||
{
|
||||
Console.Write("{0} ", CanMsgBuffer[i].Data[j].ToString("X2"));
|
||||
}
|
||||
//Console.WriteLine("");
|
||||
|
||||
//报文给高速记录的服务
|
||||
HighSpeedDataService.AppendOrUpdateMsg(new Models.HighSpeed.CommMsg()
|
||||
{
|
||||
Category = "CAN",
|
||||
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消息数据填充到信号里面,用DBC解析数据
|
||||
CAN_DBCParser.DBC_SyncCANMsgToValue(DBCHandle, msgPtRead, CanNum);
|
||||
|
||||
//循环获取消息的数据
|
||||
foreach (var item in ListCanDbcModel)
|
||||
{
|
||||
//有配置的名称的,认为是有用的,则需要读取数据
|
||||
//if (!string.IsNullOrEmpty(item.Name))
|
||||
//{
|
||||
CAN_DBCParser.DBC_GetSignalValueStr(DBCHandle, new StringBuilder(item.MsgName), new StringBuilder(item.SignalName), ValueSb);
|
||||
item.SignalRtValueSb = ValueSb;
|
||||
Console.Write(ValueSb.ToString());
|
||||
//}
|
||||
}
|
||||
|
||||
//释放数据缓冲区,必须释放,否则程序运行一段时间后会报内存不足
|
||||
Marshal.FreeHGlobal(msgPtRead);
|
||||
Thread.Sleep(10);
|
||||
|
||||
////获取信号值并打印出来
|
||||
//StringBuilder ValueStr = new StringBuilder(32);
|
||||
//CAN_DBCParser.DBC_GetSignalValueStr(DBCHandle, new StringBuilder("msg_moto_speed"), new StringBuilder("moto_speed"), ValueStr);
|
||||
//Console.WriteLine("moto_speed = {0}", ValueStr);
|
||||
//CAN_DBCParser.DBC_GetSignalValueStr(DBCHandle, new StringBuilder("msg_oil_pressure"), new StringBuilder("oil_pressure"), ValueStr);
|
||||
//Console.WriteLine("oil_pressure = {0}", ValueStr);
|
||||
//CAN_DBCParser.DBC_GetSignalValueStr(DBCHandle, new StringBuilder("msg_speed_can"), new StringBuilder("speed_can"), ValueStr);
|
||||
//Console.WriteLine("speed_can = {0}", ValueStr);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//LogService.Info($"时间:{DateTime.Now.ToString()}-【Meter】-{ex.Message}");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
#region 精确发送报文数据
|
||||
|
||||
// 添加取消标记源字段用于停止任务
|
||||
@@ -725,6 +687,7 @@ namespace CapMachine.Wpf.CanDrive
|
||||
// 严重延迟,重新校准
|
||||
NextExecutionTime = Stopwatcher.ElapsedTicks;
|
||||
Console.WriteLine("定时发送延迟过大,重新校准时间");
|
||||
LoggerService.Info($"定时发送延迟过大,重新校准时间");
|
||||
}
|
||||
|
||||
// 使用Stopwatch记录实际的执行间隔,而不是DateTime
|
||||
@@ -770,12 +733,12 @@ namespace CapMachine.Wpf.CanDrive
|
||||
if (SendedNum >= 0)
|
||||
{
|
||||
//Console.WriteLine("Success send frames:{0}", SendedNum);
|
||||
//IsSendOk = true;
|
||||
IsSendOk = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Console.WriteLine("Send CAN data failed! {0}", SendedNum);
|
||||
//IsSendOk = false;
|
||||
IsSendOk = false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -783,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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -823,7 +797,451 @@ 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 Success,SchTabIndex:{(byte)0} - Cycle:{(byte)100} - OrderSend:{(byte)1}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Start CAN Schedule 1 Error ret = {0}", ret);
|
||||
LoggerService.Info($"Start CAN Schedule 1 Error;");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//foreach (var itemGroupMsg in GroupMsg)
|
||||
//{
|
||||
// if (itemGroupMsg == null) continue;
|
||||
// if (ListCANScheduleConfig.Any(a => a.MsgName!.Contains(itemGroupMsg.Key)))
|
||||
// {
|
||||
// var CANScheduleConfig = ListCANScheduleConfig.FindFirst(a => a.MsgName!.Contains(itemGroupMsg.Key));
|
||||
// //配置表里面包括这个报文消息内容
|
||||
// ret = USB2CAN.CAN_StartSchedule(DevHandle, WriteCANIndex, (byte)CANScheduleConfig.SchTabIndex, (byte)CANScheduleConfig.Cycle, (byte)CANScheduleConfig.OrderSend);
|
||||
// if (ret == USB2CAN.CAN_SUCCESS)
|
||||
// {
|
||||
// Console.WriteLine($"Start CAN Schedule 1 Success,SchTabIndex:{(byte)CANScheduleConfig.SchTabIndex} - Cycle:{(byte)CANScheduleConfig.Cycle} - OrderSend:{(byte)CANScheduleConfig.OrderSend}");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Console.WriteLine("Start CAN Schedule 1 Error ret = {0}", ret);
|
||||
// LoggerService.Info($"Start CAN Schedule 1 Error;消息名称:{CANScheduleConfig.MsgName}");
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// LoggerService.Info($"调度表配置未发现对应的消息报文信息;报文信息{itemGroupMsg.Key}");
|
||||
// }
|
||||
//}
|
||||
|
||||
//走到这里说明调度表执行的是OK的
|
||||
//IsSendOk = true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <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消息
|
||||
/// </summary>
|
||||
public void StartCycleReviceCanMsg()
|
||||
{
|
||||
CycleReviceTask = Task.Run(async () =>
|
||||
{
|
||||
while (IsCycleRevice)
|
||||
{
|
||||
await Task.Delay(ReviceCycle);
|
||||
try
|
||||
{
|
||||
//另外一个CAN通道读取数据
|
||||
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++)
|
||||
{
|
||||
//CanMsgBuffer[i] = (USB2CAN.CAN_MSG)Marshal.PtrToStructure((IntPtr)((UInt32)msgPtRead + i * Marshal.SizeOf(typeof(USB2CAN.CAN_MSG))), typeof(USB2CAN.CAN_MSG)); //有溢出报错
|
||||
CanMsgBuffer[i] = (USB2CAN.CAN_MSG)Marshal.PtrToStructure((IntPtr)(msgPtRead + i * Marshal.SizeOf(typeof(USB2CAN.CAN_MSG))), typeof(USB2CAN.CAN_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].DataLen; j++)
|
||||
{
|
||||
Console.Write("{0} ", CanMsgBuffer[i].Data[j].ToString("X2"));
|
||||
}
|
||||
Console.WriteLine("");
|
||||
|
||||
//报文给高速记录的服务
|
||||
HighSpeedDataService.AppendOrUpdateMsg(new Models.HighSpeed.CommMsg()
|
||||
{
|
||||
Category = "CAN",
|
||||
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)
|
||||
{
|
||||
IsReviceOk = false;
|
||||
Console.WriteLine("No CAN data!");
|
||||
}
|
||||
else
|
||||
{
|
||||
IsReviceOk = false;
|
||||
Console.WriteLine("Get CAN data error!");
|
||||
}
|
||||
//Console.WriteLine("");
|
||||
|
||||
//将CAN消息数据填充到信号里面,用DBC解析数据
|
||||
CAN_DBCParser.DBC_SyncCANMsgToValue(DBCHandle, msgPtRead, CanNum);
|
||||
|
||||
//循环获取消息的数据
|
||||
foreach (var item in ListCanDbcModel)
|
||||
{
|
||||
//有配置的名称的,认为是有用的,则需要读取数据
|
||||
//if (!string.IsNullOrEmpty(item.Name))
|
||||
//{
|
||||
//CAN_DBCParser.DBC_GetSignalValueStr(DBCHandle, new StringBuilder(item.MsgName), new StringBuilder(item.SignalName), ValueSb);
|
||||
//double[] ValueDouble;
|
||||
CAN_DBCParser.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);
|
||||
//CAN_DBCParser.DBC_GetSignalValueStr(DBCHandle, new StringBuilder("msg_moto_speed"), new StringBuilder("moto_speed"), ValueStr);
|
||||
//Console.WriteLine("moto_speed = {0}", ValueStr);
|
||||
//CAN_DBCParser.DBC_GetSignalValueStr(DBCHandle, new StringBuilder("msg_oil_pressure"), new StringBuilder("oil_pressure"), ValueStr);
|
||||
//Console.WriteLine("oil_pressure = {0}", ValueStr);
|
||||
//CAN_DBCParser.DBC_GetSignalValueStr(DBCHandle, new StringBuilder("msg_speed_can"), new StringBuilder("speed_can"), ValueStr);
|
||||
//Console.WriteLine("speed_can = {0}", ValueStr);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
IsReviceOk = false;
|
||||
LoggerService.Info("接收出现异常");
|
||||
}
|
||||
//finally
|
||||
//{
|
||||
// IsReviceOk = false;
|
||||
//}
|
||||
}
|
||||
IsReviceOk = false;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 接受CAN消息
|
||||
@@ -884,6 +1302,10 @@ namespace CapMachine.Wpf.CanDrive
|
||||
DbcParserState = false;
|
||||
IsCycleRevice = false;
|
||||
IsCycleSend = false;
|
||||
if (SchEnable)
|
||||
{
|
||||
StopSchedule();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user