ToomossCan 返回值的监控日志

This commit is contained in:
2025-10-17 16:39:16 +08:00
parent 663defc0ff
commit 080d8e1ffa
4 changed files with 354 additions and 189 deletions

View File

@@ -23,6 +23,7 @@ using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Interop;
using static CapMachine.Wpf.CanDrive.USB2CAN;
using CapMachine.Wpf.Models;
namespace CapMachine.Wpf.CanDrive
{
@@ -36,11 +37,13 @@ namespace CapMachine.Wpf.CanDrive
/// <summary>
/// 实例化函数
/// </summary>
public ToomossCan(IContainerProvider containerProvider)
public ToomossCan(IContainerProvider containerProvider, ILogService logService)
{
ContainerProvider = containerProvider;
HighSpeedDataService = ContainerProvider.Resolve<HighSpeedDataService>();
LoggerService = ContainerProvider.Resolve<ILogService>();
LoggerService = logService;
monitorValueLog = new MonitorValueLog(logService, "SetSignalValue", "SyncValueToCanMsg", "ret", "CanNum", "SyncCANMsgToValue");
//Stopwatch.Frequency表示高精度计时器每秒的计数次数ticks/秒每毫秒的ticks数 = 每秒的ticks数 ÷ 1000
TicksPerMs = Stopwatch.Frequency / 1000.0;
@@ -58,6 +61,7 @@ namespace CapMachine.Wpf.CanDrive
GetCANConfig();
InitCAN();
//LoggerService.Info($"Start CAN Drive");
}
/// <summary>
@@ -568,120 +572,6 @@ namespace CapMachine.Wpf.CanDrive
/// </summary>
public List<CanCmdData> CmdData { get; set; } = new List<CanCmdData>();
/// <summary>
/// 加载要发送的数据
/// 一般是激活后才注册事件
/// </summary>
/// <param name="cmdData"></param>
public void LoadCmdDataToDrive(List<CanCmdData> cmdData)
{
// Unsubscribe from events on the old CmdData items
if (CmdData != null && CmdData.Count > 0)
{
foreach (var cmd in CmdData)
{
cmd.CanCmdDataChangedHandler -= CmdData_CanCmdDataChangedHandler;
}
}
// Set the new data and subscribe to events
CmdData = cmdData;
foreach (var cmd in cmdData)
{
cmd.CanCmdDataChangedHandler += CmdData_CanCmdDataChangedHandler;
}
}
/// <summary>
/// 指令数据发生变化执行方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void CmdData_CanCmdDataChangedHandler(object? sender, string e)
{
UpdateSchDataByCmdDataChanged();
}
/// <summary>
/// 指令数据发生变化执行更新调度表锁
/// </summary>
private readonly object SchUpdateLock = new object();
/// <summary>
/// 指令数据发生变化执行方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void UpdateSchDataByCmdDataChanged()
{
try
{
if (!IsCycleSend) return;
if (!SchEnable) return;
// 基础防御:确保 DBC/ 调度表 / 分组已经初始化
if (DBCHandle == 0 || SchCanMsg == null || GroupMsg == null)
{
return;
}
lock (SchUpdateLock)
{
//通过DBC进行对消息赋值
IntPtr msgPtSend = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CAN.CAN_MSG)));
int 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;
}
}
}
catch (Exception ex)
{
IsSendOk = false;
LoggerService.Info($"时间:{DateTime.Now.ToString()}-【MSG】-{ex.Message}");
}
}
/// <summary>
/// 循环发送数据
/// </summary>
@@ -997,6 +887,11 @@ namespace CapMachine.Wpf.CanDrive
Random random = new Random();
/// <summary>
/// 监控数据
/// </summary>
public MonitorValueLog monitorValueLog { get; set; }
/// <summary>
/// 更新数据 测试用废弃了
/// </summary>
@@ -1279,6 +1174,126 @@ namespace CapMachine.Wpf.CanDrive
}
/// <summary>
/// 加载要发送的数据
/// 一般是激活后才注册事件
/// </summary>
/// <param name="cmdData"></param>
public void LoadCmdDataToDrive(List<CanCmdData> cmdData)
{
// Unsubscribe from events on the old CmdData items
if (CmdData != null && CmdData.Count > 0)
{
foreach (var cmd in CmdData)
{
cmd.CanCmdDataChangedHandler -= CmdData_CanCmdDataChangedHandler;
}
}
// Set the new data and subscribe to events
CmdData = cmdData;
foreach (var cmd in cmdData)
{
cmd.CanCmdDataChangedHandler += CmdData_CanCmdDataChangedHandler;
}
}
/// <summary>
/// 指令数据发生变化执行方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void CmdData_CanCmdDataChangedHandler(object? sender, string e)
{
UpdateSchDataByCmdDataChanged();
}
/// <summary>
/// 指令数据发生变化执行更新调度表锁
/// </summary>
private readonly object SchUpdateLock = new object();
/// <summary>
/// 指令数据发生变化执行方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void UpdateSchDataByCmdDataChanged()
{
try
{
if (!IsCycleSend) return;
if (!SchEnable) return;
// 基础防御:确保 DBC/ 调度表 / 分组已经初始化
if (DBCHandle == 0 || SchCanMsg == null || GroupMsg == null)
{
return;
}
lock (SchUpdateLock)
{
//通过DBC进行对消息赋值
IntPtr msgPtSend = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CAN.CAN_MSG)));
int CycleUpdateIndex = 0;
//循环给MSG赋值数据顺序是固定的跟初始时设置是一样的
foreach (var itemMsg in GroupMsg)
{
foreach (var itemSignal in itemMsg)
{
//itemSignal.SignalCmdValue = random.Next(0, 100); //仿真测试数据使用
var SetSignalValue = CAN_DBCParser.DBC_SetSignalValue(DBCHandle, new StringBuilder(itemMsg.Key), new StringBuilder(itemSignal.SignalName), itemSignal.SignalCmdValue);
monitorValueLog.UpdateValue1(SetSignalValue);
}
var SyncValueToCanMsg = CAN_DBCParser.DBC_SyncValueToCANMsg(DBCHandle, new StringBuilder(itemMsg.Key), msgPtSend);
monitorValueLog.UpdateValue2(SyncValueToCanMsg);
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)}");
monitorValueLog.UpdateValue3(ret);
LoggerService.Info($"更新调度表失败,错误码:{ret}");
//return;
}
}
}
catch (Exception ex)
{
IsSendOk = false;
LoggerService.Info($"时间:{DateTime.Now.ToString()}-【MSG】-{ex.Message}");
}
}
#endregion
/// <summary>
@@ -1291,7 +1306,7 @@ namespace CapMachine.Wpf.CanDrive
{
return;
}
//monitorValueLog
CycleReviceTask = Task.Run(async () =>
{
try
@@ -1301,91 +1316,95 @@ namespace CapMachine.Wpf.CanDrive
await Task.Delay(ReviceCycle);
try
{
// 另一个CAN通道读取数据与 CloseDevice 释放互斥,保护指针安全)
IntPtr msgPtRead;
int CanNum;
lock (RecvBufferSync)
{
if (RecvMsgBufferPtr == IntPtr.Zero)
// 另一个CAN通道读取数据与 CloseDevice 释放互斥,保护指针安全)
IntPtr msgPtRead;
int CanNum;
lock (RecvBufferSync)
{
RecvMsgBufferPtr = Marshal.AllocHGlobal(CanMsgSize * RecvMsgBufferCapacity);
}
msgPtRead = RecvMsgBufferPtr;
CanNum = USB2CAN.CAN_GetMsgWithSize(DevHandle, ReadCANIndex, msgPtRead, RecvMsgBufferCapacity);
//int CanNum = USB2CAN.CAN_GetMsgWithSize(DevHandle, 1, msgPtRead, RecvMsgBufferCapacity);//测试用CAN卡 CAN1和CAN2 短接时测试用
if (CanNum > 0)
{
IsReviceOk = true;
if (EnableConsoleDebugLog) Console.WriteLine("Read CanMsgNum = {0}", CanNum);
for (int i = 0; i < CanNum; i++)
if (RecvMsgBufferPtr == IntPtr.Zero)
{
var msgPtr = (IntPtr)(msgPtRead + i * CanMsgSize);
var msg = (USB2CAN.CAN_MSG)Marshal.PtrToStructure(msgPtr, typeof(USB2CAN.CAN_MSG));
if (EnableConsoleDebugLog)
{
Console.WriteLine("CanMsg[{0}].ID = 0x{1}", i, msg.ID.ToString("X8"));
Console.WriteLine("CanMsg[{0}].TimeStamp = {1}", i, msg.TimeStamp);
Console.Write("CanMsg[{0}].Data = ", i);
for (int j = 0; j < msg.DataLen; j++)
{
Console.Write("{0} ", msg.Data[j].ToString("X2"));
}
Console.WriteLine("");
}
// 报文给高速记录的服务
HighSpeedDataService.AppendOrUpdateMsg(new Models.HighSpeed.CommMsg()
{
Category = "CAN",
MsgInfo = "0x" + msg.ID.ToString("X8"),
MsgData = BitConverter.ToString(msg.Data),
Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")
});
RecvMsgBufferPtr = Marshal.AllocHGlobal(CanMsgSize * RecvMsgBufferCapacity);
LoggerService.Info("申请 RecvMsgBufferPtr");
}
}
else if (CanNum == 0)
{
IsReviceOk = false;
if (EnableConsoleDebugLog) Console.WriteLine("No CAN data!");
}
else
{
IsReviceOk = false;
if (EnableConsoleDebugLog) Console.WriteLine("Get CAN data error!");
}
// 将CAN消息数据填充到信号里面用DBC解析数据仍在锁内避免指针被并发释放
CAN_DBCParser.DBC_SyncCANMsgToValue(DBCHandle, msgPtRead, CanNum);
}
msgPtRead = RecvMsgBufferPtr;
CanNum = USB2CAN.CAN_GetMsgWithSize(DevHandle, ReadCANIndex, msgPtRead, RecvMsgBufferCapacity);
//int CanNum = USB2CAN.CAN_GetMsgWithSize(DevHandle, 1, msgPtRead, RecvMsgBufferCapacity);//测试用CAN卡 CAN1和CAN2 短接时测试用
monitorValueLog.UpdateValue4(CanNum);
if (CanNum > 0)
{
IsReviceOk = true;
if (EnableConsoleDebugLog) Console.WriteLine("Read CanMsgNum = {0}", CanNum);
for (int i = 0; i < CanNum; i++)
{
var msgPtr = (IntPtr)(msgPtRead + i * CanMsgSize);
var msg = (USB2CAN.CAN_MSG)Marshal.PtrToStructure(msgPtr, typeof(USB2CAN.CAN_MSG));
//循环获取消息的数据
foreach (var item in ListCanDbcModel)
{
// 复用 StringBuilder 缓存,避免频繁分配
var msgNameSB = GetMsgSB(item.MsgName);
var sigNameSB = GetSigSB(item.SignalName);
CAN_DBCParser.DBC_GetSignalValue(DBCHandle, msgNameSB, sigNameSB, ValueDouble);
item.SignalRtValue = ValueDouble[0].ToString();
//Console.Write(ValueSb.ToString());
}
// 缓冲区在 CloseDevice 或任务退出的 finally 中统一释放,避免频繁申请/释放
if (EnableConsoleDebugLog)
{
Console.WriteLine("CanMsg[{0}].ID = 0x{1}", i, msg.ID.ToString("X8"));
Console.WriteLine("CanMsg[{0}].TimeStamp = {1}", i, msg.TimeStamp);
Console.Write("CanMsg[{0}].Data = ", i);
for (int j = 0; j < msg.DataLen; j++)
{
Console.Write("{0} ", msg.Data[j].ToString("X2"));
}
Console.WriteLine("");
}
// 报文给高速记录的服务
HighSpeedDataService.AppendOrUpdateMsg(new Models.HighSpeed.CommMsg()
{
Category = "CAN",
MsgInfo = "0x" + msg.ID.ToString("X8"),
MsgData = BitConverter.ToString(msg.Data),
Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")
});
}
}
else if (CanNum == 0)
{
IsReviceOk = false;
if (EnableConsoleDebugLog) Console.WriteLine("No CAN data!");
}
else
{
IsReviceOk = false;
if (EnableConsoleDebugLog) Console.WriteLine("Get CAN data error!");
}
// 将CAN消息数据填充到信号里面用DBC解析数据仍在锁内避免指针被并发释放
var SyncCANMsgToValue = CAN_DBCParser.DBC_SyncCANMsgToValue(DBCHandle, msgPtRead, CanNum);
monitorValueLog.UpdateValue5(SyncCANMsgToValue);
}
//循环获取消息的数据
foreach (var item in ListCanDbcModel)
{
// 复用 StringBuilder 缓存,避免频繁分配
var msgNameSB = GetMsgSB(item.MsgName);
var sigNameSB = GetSigSB(item.SignalName);
CAN_DBCParser.DBC_GetSignalValue(DBCHandle, msgNameSB, sigNameSB, ValueDouble);
item.SignalRtValue = ValueDouble[0].ToString();
//Console.Write(ValueSb.ToString());
}
// 缓冲区在 CloseDevice 或任务退出的 finally 中统一释放,避免频繁申请/释放
}
catch (Exception ex)
{
IsReviceOk = false;
LoggerService.Info("接收出现异常");
LoggerService.Info($"CAN指令接收出现异常:{ex.Message}");
}
//finally
//{
// IsReviceOk = false;
//}
//finally
//{
// IsReviceOk = false;
//}
}
}
finally
{
IsReviceOk = false;
LoggerService.Info("CAN指令接收 finally结束");
// 接收任务退出时释放接收缓冲,避免仅停止接收时的缓冲常驻
lock (RecvBufferSync)
{