canbug修复
This commit is contained in:
@@ -117,13 +117,23 @@ namespace MonitorModule.ViewModels.Dialogs
|
||||
EnsureValueLimit(fingerprint, displayName, displayName, methodName);
|
||||
}
|
||||
|
||||
// 3. 发现 CAN 信号并加入 ValueLimitList / DeviceSingleList
|
||||
// 3. 发现 CAN 信号并加入 ValueLimitList,同时收集有效信号名
|
||||
var validCanSignalNames = new HashSet<string>();
|
||||
foreach (var (displayName, fingerprint, methodName) in DiscoverCanSignals())
|
||||
{
|
||||
//DeviceSingleList.Add(displayName);
|
||||
_canSignalMap[displayName] = (fingerprint, methodName);
|
||||
EnsureValueLimit(fingerprint, displayName, displayName, methodName);
|
||||
validCanSignalNames.Add(displayName);
|
||||
}
|
||||
|
||||
// 4. 清理已不存在于 DBC 中的 CAN 信号(Fingerprint 以 "CAN" 开头且不在有效集合中)
|
||||
var staleCanSignals = ValueLimitList
|
||||
.Where(x => !string.IsNullOrEmpty(x.Fingerprint) &&
|
||||
x.Fingerprint.StartsWith("CAN") &&
|
||||
!validCanSignalNames.Contains(x.SignalName))
|
||||
.ToList();
|
||||
foreach (var item in staleCanSignals)
|
||||
ValueLimitList.Remove(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace UIShare.UIViewModel
|
||||
if (_series != null)
|
||||
{
|
||||
_series.Points.Add(new DataPoint(time, displayValue));
|
||||
while (_series.Points.Count > 200)
|
||||
while (_series.Points.Count > 10000)
|
||||
{
|
||||
_series.Points.RemoveAt(0);
|
||||
}
|
||||
|
||||
@@ -25,10 +25,11 @@ namespace ZLGUSBCANFD
|
||||
|
||||
// 异步高性能接收线程控制
|
||||
private volatile bool _isRunning = false;
|
||||
private volatile bool _isClosing = false; // 关闭流程标志:通知循环发送任务尽快退出
|
||||
private readonly List<Thread> _receiveThreads = new List<Thread>();
|
||||
|
||||
// DBC 循环发送任务管理:Key = (通道号, 帧ID)
|
||||
private readonly ConcurrentDictionary<(uint 通道号, uint 帧ID), CancellationTokenSource> _cyclicSenders = new ConcurrentDictionary<(uint, uint), CancellationTokenSource>();
|
||||
// DBC 循环发送任务管理:Key = (通道号, 帧ID),Value = (CTS, Task)
|
||||
private readonly ConcurrentDictionary<(uint 通道号, uint 帧ID), (CancellationTokenSource Cts, Task SendTask)> _cyclicSenders = new ConcurrentDictionary<(uint, uint), (CancellationTokenSource, Task)>();
|
||||
|
||||
// 信号值持久化覆盖表:Key = (通道号, 帧ID),Value = 信号名 → 物理值
|
||||
// 每次 设置报文 会累积写入此表,发送时以 DBC 初始值为底再叠加此表覆盖值
|
||||
@@ -98,15 +99,17 @@ namespace ZLGUSBCANFD
|
||||
/// </summary>
|
||||
public virtual bool 初始化并启动通道(uint 通道号)
|
||||
{
|
||||
_isClosing = false; // 重置关闭标志,允许循环发送
|
||||
if (_deviceHandle == IntPtr.Zero) throw new InvalidOperationException("请先调用 '打开设备()' 才能初始化通道。");
|
||||
if (通道号 >= _maxChannels) return false;
|
||||
|
||||
lock (_channelLocks[通道号])
|
||||
{
|
||||
// 如果已经启动过,先复位
|
||||
// 如果已经启动过,直接退出
|
||||
if (_channelHandles[通道号] != IntPtr.Zero)
|
||||
{
|
||||
ZLGCAN.ZCAN_ResetCAN(_channelHandles[通道号]);
|
||||
return true;
|
||||
//ZLGCAN.ZCAN_ResetCAN(_channelHandles[通道号]);
|
||||
}
|
||||
|
||||
// 1. 设置该通道专属的仲裁域与数据域波特率
|
||||
@@ -150,19 +153,44 @@ namespace ZLGUSBCANFD
|
||||
|
||||
public virtual void 关闭CAN卡设备()
|
||||
{
|
||||
_isRunning = false;
|
||||
停止所有循环发送();
|
||||
Thread.Sleep(50); // 确保轮询线程安全退出
|
||||
_isClosing = true; // 通知循环发送任务尽快退出
|
||||
_isRunning = false; // 通知接收轮询线程退出
|
||||
停止所有循环发送(); // 内部会等待所有循环发送 Task 退出
|
||||
|
||||
// 等待所有接收轮询线程真正退出(每个最多 1 秒)
|
||||
foreach (var thread in _receiveThreads)
|
||||
{
|
||||
if (thread.IsAlive)
|
||||
thread.Join(1000);
|
||||
}
|
||||
_receiveThreads.Clear();
|
||||
|
||||
//动态复位所有通道并释放DBC
|
||||
// 动态复位所有通道并释放 DBC(使用 TryEnter 防止死锁)
|
||||
for (uint i = 0; i < _maxChannels; i++)
|
||||
{
|
||||
lock (_channelLocks[i])
|
||||
if (Monitor.TryEnter(_channelLocks[i], TimeSpan.FromSeconds(2)))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_channelHandles[i] != IntPtr.Zero)
|
||||
{
|
||||
ZLGCAN.ZCAN_ResetCAN(_channelHandles[i]);
|
||||
_channelHandles[i] = IntPtr.Zero;
|
||||
}
|
||||
释放通道DBC(i);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Monitor.Exit(_channelLocks[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 锁超时:循环发送 Task 可能仍阻塞在原生 API 调用中,强制清理
|
||||
LoggerHelper.Info($"[ZLGCANFD] 关闭通道 {i} 时获取锁超时,强制清理");
|
||||
if (_channelHandles[i] != IntPtr.Zero)
|
||||
{
|
||||
ZLGCAN.ZCAN_ResetCAN(_channelHandles[i]);
|
||||
try { ZLGCAN.ZCAN_ResetCAN(_channelHandles[i]); } catch { }
|
||||
_channelHandles[i] = IntPtr.Zero;
|
||||
}
|
||||
释放通道DBC(i);
|
||||
@@ -175,6 +203,8 @@ namespace ZLGUSBCANFD
|
||||
ZLGCAN.ZCAN_CloseDevice(_deviceHandle);
|
||||
_deviceHandle = IntPtr.Zero;
|
||||
}
|
||||
|
||||
_isClosing = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -354,17 +384,16 @@ namespace ZLGUSBCANFD
|
||||
停止循环发送(通道号, 帧ID);
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
_cyclicSenders[(通道号, 帧ID)] = cts;
|
||||
|
||||
Task.Run(async () =>
|
||||
var sendTask = Task.Run(async () =>
|
||||
{
|
||||
while (!cts.Token.IsCancellationRequested)
|
||||
{
|
||||
if (_isClosing) break; // 关闭流程中立即退出
|
||||
try
|
||||
{
|
||||
lock (_channelLocks[通道号])
|
||||
{
|
||||
if (_channelHandles[通道号] == IntPtr.Zero) break;
|
||||
if (_channelHandles[通道号] == IntPtr.Zero || _isClosing) break;
|
||||
发送DBC定义报文单次(通道号, 帧ID, 信号物理值字典, 是否使用CANFD);
|
||||
}
|
||||
|
||||
@@ -382,13 +411,15 @@ namespace ZLGUSBCANFD
|
||||
}
|
||||
|
||||
// 清理:仅当字典中存的仍然是本任务创建的 CTS 时才移除,避免误删新任务的 CTS
|
||||
if (_cyclicSenders.TryGetValue((通道号, 帧ID), out var current) && ReferenceEquals(current, cts))
|
||||
if (_cyclicSenders.TryGetValue((通道号, 帧ID), out var current) && ReferenceEquals(current.Cts, cts))
|
||||
{
|
||||
_cyclicSenders.TryRemove((通道号, 帧ID), out _);
|
||||
}
|
||||
cts.Dispose();
|
||||
}, cts.Token);
|
||||
|
||||
_cyclicSenders[(通道号, 帧ID)] = (cts, sendTask);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -397,9 +428,9 @@ namespace ZLGUSBCANFD
|
||||
/// </summary>
|
||||
public virtual void 停止循环发送(uint 通道号, uint 帧ID)
|
||||
{
|
||||
if (_cyclicSenders.TryRemove((通道号, 帧ID), out var cts))
|
||||
if (_cyclicSenders.TryRemove((通道号, 帧ID), out var entry))
|
||||
{
|
||||
cts.Cancel();
|
||||
entry.Cts.Cancel();
|
||||
// 不在这里 Dispose,由 Task 的清理代码负责释放,避免 Task 仍在使用已释放的 Token
|
||||
}
|
||||
}
|
||||
@@ -409,11 +440,30 @@ namespace ZLGUSBCANFD
|
||||
/// </summary>
|
||||
public virtual void 停止所有循环发送()
|
||||
{
|
||||
foreach (var kvp in _cyclicSenders)
|
||||
var entries = _cyclicSenders.ToArray();
|
||||
|
||||
// 1. 取消所有 CTS(不 Dispose,由 Task 清理代码负责)
|
||||
foreach (var kvp in entries)
|
||||
{
|
||||
kvp.Value.Cancel();
|
||||
kvp.Value.Dispose();
|
||||
kvp.Value.Cts.Cancel();
|
||||
}
|
||||
|
||||
// 2. 等待所有循环发送 Task 退出(最多 3 秒)
|
||||
var tasks = new List<Task>();
|
||||
foreach (var kvp in entries)
|
||||
{
|
||||
if (!kvp.Value.SendTask.IsCompleted)
|
||||
tasks.Add(kvp.Value.SendTask);
|
||||
}
|
||||
if (tasks.Count > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
Task.WaitAll(tasks.ToArray(), TimeSpan.FromSeconds(3));
|
||||
}
|
||||
catch { /* 忽略等待异常 */ }
|
||||
}
|
||||
|
||||
_cyclicSenders.Clear();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user