From e392527592873324735311025daa4a36eef6dc34 Mon Sep 17 00:00:00 2001 From: hsc Date: Thu, 13 Aug 2026 13:35:43 +0800 Subject: [PATCH] =?UTF-8?q?=E7=8E=B0=E5=9C=BA=E4=BC=98=E5=8C=962?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ViewModels/BenchMovementViewModel.cs | 60 ++-- CANModule/ViewModels/ZLGCANFDViewModel.cs | 28 ++ DeviceCommand/Devices/GantryControlTcp.cs | 262 +++++++++--------- ZLGUSBCANFD/USBCANFD.cs | 14 + 4 files changed, 203 insertions(+), 161 deletions(-) diff --git a/BenchMovementModule/ViewModels/BenchMovementViewModel.cs b/BenchMovementModule/ViewModels/BenchMovementViewModel.cs index d1690c3..6560420 100644 --- a/BenchMovementModule/ViewModels/BenchMovementViewModel.cs +++ b/BenchMovementModule/ViewModels/BenchMovementViewModel.cs @@ -221,8 +221,8 @@ namespace BenchMovementModule.ViewModels if (!EnsureConnected()) return; try { - await _gantry!.SetAxisTargetPositionAsync(1, TargetX); - await _gantry.StartSingleAxisAsync(1); + await _gantry!.设置轴目标位置(1, TargetX); + await _gantry.启动单轴(1); LoggerHelper.Info($"[BenchMovement] X轴移动到 {TargetX}"); } catch (Exception ex) @@ -237,8 +237,8 @@ namespace BenchMovementModule.ViewModels if (!EnsureConnected()) return; try { - await _gantry!.SetAxisTargetPositionAsync(2, TargetY); - await _gantry.StartSingleAxisAsync(2); + await _gantry!.设置轴目标位置(2, TargetY); + await _gantry.启动单轴(2); LoggerHelper.Info($"[BenchMovement] Y轴移动到 {TargetY}"); } catch (Exception ex) @@ -253,8 +253,8 @@ namespace BenchMovementModule.ViewModels if (!EnsureConnected()) return; try { - await _gantry!.SetAxisTargetPositionAsync(3, TargetZ); - await _gantry.StartSingleAxisAsync(3); + await _gantry!.设置轴目标位置(3, TargetZ); + await _gantry.启动单轴(3); LoggerHelper.Info($"[BenchMovement] Z轴移动到 {TargetZ}"); } catch (Exception ex) @@ -269,10 +269,10 @@ namespace BenchMovementModule.ViewModels if (!EnsureConnected()) return; try { - await _gantry!.SetAxisTargetPositionAsync(1, TargetX); - await _gantry.SetAxisTargetPositionAsync(2, TargetY); - await _gantry.SetAxisTargetPositionAsync(3, TargetZ); - await _gantry.StartAllAxesAsync(); + await _gantry!.设置轴目标位置(1, TargetX); + await _gantry.设置轴目标位置(2, TargetY); + await _gantry.设置轴目标位置(3, TargetZ); + await _gantry.启动全部轴(); LoggerHelper.Info($"[BenchMovement] 三轴同时移动: X={TargetX}, Y={TargetY}, Z={TargetZ}"); } catch (Exception ex) @@ -287,7 +287,7 @@ namespace BenchMovementModule.ViewModels if (!EnsureConnected()) return; try { - await _gantry!.HomeAsync(); + await _gantry!.回零(); LoggerHelper.Info("[BenchMovement] 回原点已触发"); } catch (Exception ex) @@ -302,7 +302,7 @@ namespace BenchMovementModule.ViewModels if (!EnsureConnected()) return; try { - await _gantry!.SetEStopStateAsync(true); + await _gantry!.设置急停状态(true); LoggerHelper.Info("[BenchMovement] 急停已触发"); } catch (Exception ex) @@ -316,9 +316,9 @@ namespace BenchMovementModule.ViewModels if (!EnsureConnected()) return; try { - await _gantry!.SetStopStateAsync(1, true); + await _gantry!.设置轴停止状态(1, true); await Task.Delay(100); - await _gantry.SetStopStateAsync(1, false); + await _gantry.设置轴停止状态(1, false); } catch (Exception ex) { @@ -331,9 +331,9 @@ namespace BenchMovementModule.ViewModels if (!EnsureConnected()) return; try { - await _gantry!.SetStopStateAsync(2, true); + await _gantry!.设置轴停止状态(2, true); await Task.Delay(100); - await _gantry.SetStopStateAsync(2, false); + await _gantry.设置轴停止状态(2, false); } catch (Exception ex) { @@ -346,9 +346,9 @@ namespace BenchMovementModule.ViewModels if (!EnsureConnected()) return; try { - await _gantry!.SetStopStateAsync(3, true); + await _gantry!.设置轴停止状态(3, true); await Task.Delay(100); - await _gantry.SetStopStateAsync(3, false); + await _gantry.设置轴停止状态(3, false); } catch (Exception ex) { @@ -361,10 +361,10 @@ namespace BenchMovementModule.ViewModels if (!EnsureConnected()) return; try { - await _gantry!.SetAxisSpeedAsync(1, SpeedX); - await _gantry.SetAxisSpeedAsync(2, SpeedY); - await _gantry.SetAxisSpeedAsync(3, SpeedZ); - await _gantry.SetHomePositionSpeedAsync(HomeSpeed); + await _gantry!.设置轴速度(1, SpeedX); + await _gantry.设置轴速度(2, SpeedY); + await _gantry.设置轴速度(3, SpeedZ); + await _gantry.设置回零速度(HomeSpeed); LoggerHelper.Info($"[BenchMovement] 速度设定完成: X={SpeedX}, Y={SpeedY}, Z={SpeedZ}, 回零={HomeSpeed}"); } catch (Exception ex) @@ -379,7 +379,7 @@ namespace BenchMovementModule.ViewModels if (!EnsureConnected()) return; try { - await _gantry!.SetHomePositionAsync(HomeX, HomeY, HomeZ); + await _gantry!.设置原点位置(HomeX, HomeY, HomeZ); LoggerHelper.Info($"[BenchMovement] 零点设定完成: X={HomeX}, Y={HomeY}, Z={HomeZ}"); } catch (Exception ex) @@ -419,16 +419,16 @@ namespace BenchMovementModule.ViewModels if (_gantry == null || !_gantry.IsConnected) return; try { - var (x, y, z) = await _gantry.GetHomePositionAsync(); + var (x, y, z) = await _gantry.查询原点位置(); HomeX = x; HomeY = y; HomeZ = z; - SpeedX = await _gantry.GetAxisSpeedAsync(1); - SpeedY = await _gantry.GetAxisSpeedAsync(2); - SpeedZ = await _gantry.GetAxisSpeedAsync(3); - HomeSpeed = await _gantry.GetHomePositionSpeedAsync(); + SpeedX = await _gantry.查询轴速度(1); + SpeedY = await _gantry.查询轴速度(2); + SpeedZ = await _gantry.查询轴速度(3); + HomeSpeed = await _gantry.查询回零速度(); // 读取 6 轴绝对位置 - var positions = await _gantry.GetAllAbsolutePositionsAsync(); + var positions = await _gantry.查询全部轴绝对位置(); AbsPos1 = positions.Axis1; AbsPos2 = positions.Axis2; AbsPos3 = positions.Axis3; AbsPos4 = positions.Axis4; AbsPos5 = positions.Axis5; AbsPos6 = positions.Axis6; } @@ -444,7 +444,7 @@ namespace BenchMovementModule.ViewModels try { // 批量读取 6 轴绝对位置(一次性通信,高效) - var pos = await _gantry.GetAllAbsolutePositionsAsync(); + var pos = await _gantry.查询全部轴绝对位置(); AbsPos1 = pos.Axis1; AbsPos2 = pos.Axis2; AbsPos3 = pos.Axis3; AbsPos4 = pos.Axis4; AbsPos5 = pos.Axis5; AbsPos6 = pos.Axis6; } diff --git a/CANModule/ViewModels/ZLGCANFDViewModel.cs b/CANModule/ViewModels/ZLGCANFDViewModel.cs index 1ebc85e..ebc426d 100644 --- a/CANModule/ViewModels/ZLGCANFDViewModel.cs +++ b/CANModule/ViewModels/ZLGCANFDViewModel.cs @@ -347,6 +347,7 @@ namespace CANModule.ViewModels DeleteDcAutoLoadCommand = new DelegateCommand(DeleteDcAutoLoad); SendCustomMessageCommand = new DelegateCommand(SendCustomMessage); _canfd.OnDbcMessageDecoded += OnDbcMessageDecoded; + _canfd.OnRawMessageReceived += OnRawMessageReceived; LoadCommand = new DelegateCommand(Load); } @@ -368,6 +369,7 @@ namespace CANModule.ViewModels if (_canfd != null) { _canfd.OnDbcMessageDecoded -= OnDbcMessageDecoded; + _canfd.OnRawMessageReceived -= OnRawMessageReceived; } _refreshCts?.Cancel(); } @@ -627,6 +629,32 @@ namespace CANModule.ViewModels }); } + private void OnRawMessageReceived(uint channel, uint canId, byte[] data, ulong timestamp, bool isFD, byte dlcLength) + { + // 原始报文回调:不依赖 DBC,自定义报文也能收到 + Application.Current.Dispatcher.BeginInvoke(() => + { + // 提取实际 CAN ID(去掉扩展帧标志位) + int actualId = (int)(canId & 0x1FFFFFFF); + var find = CanMessageList.FirstOrDefault(s => s.报文ID == actualId && s.通道 == channel); + if (find != null) + { + find.时间戳 = (ulong)DateTimeOffset.Now.ToUnixTimeMilliseconds(); + find.长度 = dlcLength; + } + else + { + CanMessageList.Add(new CanMessageShowVM + { + 通道 = (byte)channel, + 报文ID = actualId, + 时间戳 = (ulong)DateTimeOffset.Now.ToUnixTimeMilliseconds(), + 长度 = dlcLength + }); + } + }); + } + private string 十六进制字符串转换(System.Span s) { if (s == null || s.Length == 0) diff --git a/DeviceCommand/Devices/GantryControlTcp.cs b/DeviceCommand/Devices/GantryControlTcp.cs index b339ed9..b251c3a 100644 --- a/DeviceCommand/Devices/GantryControlTcp.cs +++ b/DeviceCommand/Devices/GantryControlTcp.cs @@ -84,12 +84,12 @@ namespace DeviceCommand.Devices /// /// 轴使能控制 /// - /// 轴编号 (1 - 6) - /// true: 使能轴, false: 禁用轴 - /// 取消令牌 - public async Task SetAxisEnableAsync(int axis, bool enable, CancellationToken ct = default) + /// 轴编号 (1 - 6) + /// true: 使能轴, false: 禁用轴 + /// 取消令牌 + public async Task 设置轴使能(int 轴编号, bool 使能, CancellationToken 取消令牌 = default) { - ushort address = axis switch + ushort address = 轴编号 switch { 1 => ADDR_HM_AXIS1_ENABLE, 2 => ADDR_HM_AXIS2_ENABLE, @@ -97,64 +97,64 @@ namespace DeviceCommand.Devices 4 => ADDR_HM_AXIS4_ENABLE, 5 => ADDR_HM_AXIS5_ENABLE, 6 => ADDR_HM_AXIS6_ENABLE, - _ => throw new ArgumentException("轴通道错误,仅支持 1 - 6", nameof(axis)) + _ => throw new ArgumentException("轴通道错误,仅支持 1 - 6", nameof(轴编号)) }; - await WriteSingleCoilAsync(_slaveAddress, address, enable, ct); + await WriteSingleCoilAsync(_slaveAddress, address, 使能, 取消令牌); } /// /// 读取指定轴的使能状态 /// - /// 1: X轴, 2: Y轴, 3: Z轴 - /// 取消令牌 + /// 1: X轴, 2: Y轴, 3: Z轴 + /// 取消令牌 /// true: 已使能, false: 未使能 - public async Task GetAxisEnableAsync(int axis, CancellationToken ct = default) + public async Task 查询轴使能(int 轴编号, CancellationToken 取消令牌 = default) { - ushort address = axis switch + ushort address = 轴编号 switch { 1 => ADDR_HM_AXIS1_ENABLE, 2 => ADDR_HM_AXIS2_ENABLE, 3 => ADDR_HM_AXIS3_ENABLE, - _ => throw new ArgumentException("轴通道错误,仅支持 1(X), 2(Y), 3(Z)", nameof(axis)) + _ => throw new ArgumentException("轴通道错误,仅支持 1(X), 2(Y), 3(Z)", nameof(轴编号)) }; - bool[] coils = await ReadCoilsAsync(_slaveAddress, address, 1, ct); + bool[] coils = await ReadCoilsAsync(_slaveAddress, address, 1, 取消令牌); return coils != null && coils.Length > 0 && coils[0]; } /// /// 同时设置 X/Y/Z 轴的原点位置(带各自独立的范围检查) /// - /// X轴原点位置 (范围: 0 ~ 50000) - /// Y轴原点位置 (范围: 0 ~ 50000) - /// Z轴原点位置 (范围: 0 ~ 20000) - /// 取消令牌 - public async Task SetHomePositionAsync(int xPos, int yPos, int zPos, CancellationToken ct = default) + /// X轴原点位置 (范围: 0 ~ 50000) + /// Y轴原点位置 (范围: 0 ~ 50000) + /// Z轴原点位置 (范围: 0 ~ 20000) + /// 取消令牌 + public async Task 设置原点位置(int X轴原点, int Y轴原点, int Z轴原点, CancellationToken 取消令牌 = default) { - if (xPos < 0 || xPos > 50000) - throw new ArgumentOutOfRangeException(nameof(xPos), $"X轴原点设置值 [{xPos}] 超出合法范围 (0 - 50000)"); + if (X轴原点 < 0 || X轴原点 > 50000) + throw new ArgumentOutOfRangeException(nameof(X轴原点), $"X轴原点设置值 [{X轴原点}] 超出合法范围 (0 - 50000)"); - if (yPos < 0 || yPos > 50000) - throw new ArgumentOutOfRangeException(nameof(yPos), $"Y轴原点设置值 [{yPos}] 超出合法范围 (0 - 50000)"); + if (Y轴原点 < 0 || Y轴原点 > 50000) + throw new ArgumentOutOfRangeException(nameof(Y轴原点), $"Y轴原点设置值 [{Y轴原点}] 超出合法范围 (0 - 50000)"); - if (zPos < 0 || zPos > 20000) - throw new ArgumentOutOfRangeException(nameof(zPos), $"Z轴原点设置值 [{zPos}] 超出合法范围 (0 - 20000)"); + if (Z轴原点 < 0 || Z轴原点 > 20000) + throw new ArgumentOutOfRangeException(nameof(Z轴原点), $"Z轴原点设置值 [{Z轴原点}] 超出合法范围 (0 - 20000)"); - await WriteMultipleRegistersAsync(_slaveAddress, ADDR_HD_X_HOME_POS, Int32ToUshorts(xPos), ct); - await WriteMultipleRegistersAsync(_slaveAddress, ADDR_HD_Y_HOME_POS, Int32ToUshorts(yPos), ct); - await WriteMultipleRegistersAsync(_slaveAddress, ADDR_HD_Z_HOME_POS, Int32ToUshorts(zPos), ct); + await WriteMultipleRegistersAsync(_slaveAddress, ADDR_HD_X_HOME_POS, Int32ToUshorts(X轴原点), 取消令牌); + await WriteMultipleRegistersAsync(_slaveAddress, ADDR_HD_Y_HOME_POS, Int32ToUshorts(Y轴原点), 取消令牌); + await WriteMultipleRegistersAsync(_slaveAddress, ADDR_HD_Z_HOME_POS, Int32ToUshorts(Z轴原点), 取消令牌); } /// /// 批量查询当前 X、Y、Z 三轴设定的原点位置值 /// - /// 取消令牌 + /// 取消令牌 /// 返回包含三轴原点位置的元组 (X, Y, Z) - public async Task<(int X, int Y, int Z)> GetHomePositionAsync(CancellationToken ct = default) + public async Task<(int X, int Y, int Z)> 查询原点位置(CancellationToken 取消令牌 = default) { // 41218(Y) - 41198(X) = 20,加Y轴自身的 2 个寄存器,共批量读取 22 个连续寄存器 - ushort[] registers = await ReadHoldingRegistersAsync(_slaveAddress, ADDR_HD_X_HOME_POS, 22, ct); + ushort[] registers = await ReadHoldingRegistersAsync(_slaveAddress, ADDR_HD_X_HOME_POS, 22, 取消令牌); if (registers == null || registers.Length < 22) throw new InvalidOperationException("从 PLC 读取三轴原点位置失败,返回数据长度不足。"); @@ -169,24 +169,24 @@ namespace DeviceCommand.Devices /// /// 设置回原点定位速度(带 0 - 100000 范围检查) /// - /// 回原点定位速度 (范围: 0 - 100000) - /// 取消令牌 - public async Task SetHomePositionSpeedAsync(int speed, CancellationToken ct = default) + /// 回原点定位速度 (范围: 0 - 100000) + /// 取消令牌 + public async Task 设置回零速度(int 速度, CancellationToken 取消令牌 = default) { - if (speed < 0 || speed > 100000) - throw new ArgumentOutOfRangeException(nameof(speed), $"回原点定位速度值 [{speed}] 超出合法范围 (0 - 100000)"); + if (速度 < 0 || 速度 > 100000) + throw new ArgumentOutOfRangeException(nameof(速度), $"回原点定位速度值 [{速度}] 超出合法范围 (0 - 100000)"); - await WriteMultipleRegistersAsync(_slaveAddress, ADDR_HD_HOME_POS_SPEED, Int32ToUshorts(speed), ct); + await WriteMultipleRegistersAsync(_slaveAddress, ADDR_HD_HOME_POS_SPEED, Int32ToUshorts(速度), 取消令牌); } /// /// 查询当前设定的回原点定位速度 /// - /// 取消令牌 + /// 取消令牌 /// 当前回原点定位速度值 - public async Task GetHomePositionSpeedAsync(CancellationToken ct = default) + public async Task 查询回零速度(CancellationToken 取消令牌 = default) { - ushort[] registers = await ReadHoldingRegistersAsync(_slaveAddress, ADDR_HD_HOME_POS_SPEED, 2, ct); + ushort[] registers = await ReadHoldingRegistersAsync(_slaveAddress, ADDR_HD_HOME_POS_SPEED, 2, 取消令牌); if (registers == null || registers.Length < 2) throw new InvalidOperationException("从 PLC 读取回原点定位速度失败,返回数据长度不足。"); @@ -197,44 +197,44 @@ namespace DeviceCommand.Devices /// /// 设置指定轴的运行速度(带 0 - 100000 范围检查) /// - /// 1: X轴, 2: Y轴, 3: Z轴 - /// 运行速度 (范围: 0 - 100000) - /// 取消令牌 - public async Task SetAxisSpeedAsync(int axis, int speed, CancellationToken ct = default) + /// 1: X轴, 2: Y轴, 3: Z轴 + /// 运行速度 (范围: 0 - 100000) + /// 取消令牌 + public async Task 设置轴速度(int 轴编号, int 速度, CancellationToken 取消令牌 = default) { - if (speed < 0 || speed > 100000) - throw new ArgumentOutOfRangeException(nameof(speed), $"轴速度设置值 [{speed}] 超出合法范围 (0 - 100000)"); + if (速度 < 0 || 速度 > 100000) + throw new ArgumentOutOfRangeException(nameof(速度), $"轴速度设置值 [{速度}] 超出合法范围 (0 - 100000)"); - ushort address = axis switch + ushort address = 轴编号 switch { 1 => ADDR_HD_X_SPEED, 2 => ADDR_HD_Y_SPEED, 3 => ADDR_HD_Z_SPEED, - _ => throw new ArgumentException("轴通道错误,仅支持 1(X), 2(Y), 3(Z)", nameof(axis)) + _ => throw new ArgumentException("轴通道错误,仅支持 1(X), 2(Y), 3(Z)", nameof(轴编号)) }; - await WriteMultipleRegistersAsync(_slaveAddress, address, Int32ToUshorts(speed), ct); + await WriteMultipleRegistersAsync(_slaveAddress, address, Int32ToUshorts(速度), 取消令牌); } /// /// 读取指定轴当前设定的运行速度 /// - /// 1: X轴, 2: Y轴, 3: Z轴 - /// 取消令牌 + /// 1: X轴, 2: Y轴, 3: Z轴 + /// 取消令牌 /// 当前设定的运行速度值 - public async Task GetAxisSpeedAsync(int axis, CancellationToken ct = default) + public async Task 查询轴速度(int 轴编号, CancellationToken 取消令牌 = default) { - ushort address = axis switch + ushort address = 轴编号 switch { 1 => ADDR_HD_X_SPEED, 2 => ADDR_HD_Y_SPEED, 3 => ADDR_HD_Z_SPEED, - _ => throw new ArgumentException("轴通道错误,仅支持 1(X), 2(Y), 3(Z)", nameof(axis)) + _ => throw new ArgumentException("轴通道错误,仅支持 1(X), 2(Y), 3(Z)", nameof(轴编号)) }; - ushort[] registers = await ReadHoldingRegistersAsync(_slaveAddress, address, 2, ct); + ushort[] registers = await ReadHoldingRegistersAsync(_slaveAddress, address, 2, 取消令牌); if (registers == null || registers.Length < 2) - throw new InvalidOperationException($"从 PLC 读取轴 {axis} 速度失败。"); + throw new InvalidOperationException($"从 PLC 读取轴 {轴编号} 速度失败。"); return UshortsToInt32(registers); } @@ -242,18 +242,18 @@ namespace DeviceCommand.Devices /// /// 写入指定轴的目标位置(动态安全校验:目标位置不能超过 [轴最大物理极限 - 当前轴原点设置值]) /// - /// 1: X轴, 2: Y轴, 3: Z轴 - /// 目标位置 - /// 取消令牌 - public async Task SetAxisTargetPositionAsync(int axis, int targetPos, CancellationToken ct = default) + /// 1: X轴, 2: Y轴, 3: Z轴 + /// 目标位置 + /// 取消令牌 + public async Task 设置轴目标位置(int 轴编号, int 目标位置, CancellationToken 取消令牌 = default) { - var (xHome, yHome, zHome) = await GetHomePositionAsync(ct); + var (xHome, yHome, zHome) = await 查询原点位置(取消令牌); ushort targetAddress; int maxLimit; int currentHomePos; - switch (axis) + switch (轴编号) { case 1: targetAddress = ADDR_HD_X_TARGET; @@ -271,42 +271,42 @@ namespace DeviceCommand.Devices currentHomePos = zHome; break; default: - throw new ArgumentException("轴通道错误,仅支持 1(X), 2(Y), 3(Z)", nameof(axis)); + throw new ArgumentException("轴通道错误,仅支持 1(X), 2(Y), 3(Z)", nameof(轴编号)); } int allowedMaxLimit = maxLimit - currentHomePos; - if (targetPos < 0 || targetPos > allowedMaxLimit) + if (目标位置 < 0 || 目标位置 > allowedMaxLimit) { throw new ArgumentOutOfRangeException( - nameof(targetPos), - $"轴 {axis} 目标位置 [{targetPos}] 不合法!当前原点为 [{currentHomePos}],允许的有效写入范围为: 0 - {allowedMaxLimit}" + nameof(目标位置), + $"轴 {轴编号} 目标位置 [{目标位置}] 不合法!当前原点为 [{currentHomePos}],允许的有效写入范围为: 0 - {allowedMaxLimit}" ); } - await WriteMultipleRegistersAsync(_slaveAddress, targetAddress, Int32ToUshorts(targetPos), ct); + await WriteMultipleRegistersAsync(_slaveAddress, targetAddress, Int32ToUshorts(目标位置), 取消令牌); } /// /// 读取指定轴当前设定的目标指定位置 /// - /// 1: X轴, 2: Y轴, 3: Z轴 - /// 取消令牌 + /// 1: X轴, 2: Y轴, 3: Z轴 + /// 取消令牌 /// 当前设定的目标位置值 - public async Task GetAxisTargetPositionAsync(int axis, CancellationToken ct = default) + public async Task 查询轴目标位置(int 轴编号, CancellationToken 取消令牌 = default) { - ushort address = axis switch + ushort address = 轴编号 switch { 1 => ADDR_HD_X_TARGET, 2 => ADDR_HD_Y_TARGET, 3 => ADDR_HD_Z_TARGET, - _ => throw new ArgumentException("轴通道错误,仅支持 1(X), 2(Y), 3(Z)", nameof(axis)) + _ => throw new ArgumentException("轴通道错误,仅支持 1(X), 2(Y), 3(Z)", nameof(轴编号)) }; - ushort[] registers = await ReadHoldingRegistersAsync(_slaveAddress, address, 2, ct); + ushort[] registers = await ReadHoldingRegistersAsync(_slaveAddress, address, 2, 取消令牌); if (registers == null || registers.Length < 2) - throw new InvalidOperationException($"从 PLC 读取轴 {axis} 目标位置失败。"); + throw new InvalidOperationException($"从 PLC 读取轴 {轴编号} 目标位置失败。"); return UshortsToInt32(registers); } @@ -314,60 +314,60 @@ namespace DeviceCommand.Devices /// /// 设置系统紧停锁定状态 (true: 锁定激活, false: 解除锁定) /// - /// true: 锁定激活, false: 解除锁定 - /// 取消令牌 - public async Task SetEStopStateAsync(bool state, CancellationToken ct = default) + /// true: 锁定激活, false: 解除锁定 + /// 取消令牌 + public async Task 设置急停状态(bool 状态, CancellationToken 取消令牌 = default) { - await WriteSingleCoilAsync(_slaveAddress, ADDR_M_ESTOP, state, ct); + await WriteSingleCoilAsync(_slaveAddress, ADDR_M_ESTOP, 状态, 取消令牌); } /// /// 设置指定轴的停止控制状态 (true: 持续输出停止信号, false: 释放停止信号) /// - /// 1: X轴, 2: Y轴, 3: Z轴 - /// true: 持续输出停止信号, false: 释放停止信号 - /// 取消令牌 - public async Task SetStopStateAsync(int axis, bool state, CancellationToken ct = default) + /// 1: X轴, 2: Y轴, 3: Z轴 + /// true: 持续输出停止信号, false: 释放停止信号 + /// 取消令牌 + public async Task 设置轴停止状态(int 轴编号, bool 状态, CancellationToken 取消令牌 = default) { - ushort address = axis switch + ushort address = 轴编号 switch { 1 => ADDR_M_X_STOP, 2 => ADDR_M_Y_STOP, 3 => ADDR_M_Z_STOP, - _ => throw new ArgumentException("轴通道错误,仅支持 1(X), 2(Y), 3(Z)", nameof(axis)) + _ => throw new ArgumentException("轴通道错误,仅支持 1(X), 2(Y), 3(Z)", nameof(轴编号)) }; - await WriteSingleCoilAsync(_slaveAddress, address, state, ct); + await WriteSingleCoilAsync(_slaveAddress, address, 状态, 取消令牌); } /// /// 全局回零(安全校验版:先检查回原点速度是否为 0,为0则拒绝触发) /// - /// 取消令牌 - public async Task HomeAsync(CancellationToken ct = default) + /// 取消令牌 + public async Task 回零(CancellationToken 取消令牌 = default) { - int currentSpeed = await GetHomePositionSpeedAsync(ct); + int currentSpeed = await 查询回零速度(取消令牌); if (currentSpeed == 0) throw new InvalidOperationException("无法触发回原点!当前回原点定位速度为 0,请先设置合法的回零速度。"); - await TriggerCoilAsync(ADDR_M_HOME_TRIGGER, ct); + await TriggerCoilAsync(ADDR_M_HOME_TRIGGER, 取消令牌); } /// /// 单轴指定位置启动(含速度判定、使能自动补齐、动作目标位置独立范围校验) /// - /// 1: X轴, 2: Y轴, 3: Z轴 - /// 取消令牌 - public async Task StartSingleAxisAsync(int axis, CancellationToken ct = default) + /// 1: X轴, 2: Y轴, 3: Z轴 + /// 取消令牌 + public async Task 启动单轴(int 轴编号, CancellationToken 取消令牌 = default) { ushort startAddress; int maxLimit; int currentHomePos; // 1. 获取基础参数与校验边界 - var (xHome, yHome, zHome) = await GetHomePositionAsync(ct); - switch (axis) + var (xHome, yHome, zHome) = await 查询原点位置(取消令牌); + switch (轴编号) { case 1: startAddress = ADDR_M_X_START; @@ -385,50 +385,50 @@ namespace DeviceCommand.Devices currentHomePos = zHome; break; default: - throw new ArgumentException("轴通道错误,仅支持 1(X), 2(Y), 3(Z)", nameof(axis)); + throw new ArgumentException("轴通道错误,仅支持 1(X), 2(Y), 3(Z)", nameof(轴编号)); } // 2. 检查动作轴的速度 - int currentSpeed = await GetAxisSpeedAsync(axis, ct); + int currentSpeed = await 查询轴速度(轴编号, 取消令牌); if (currentSpeed == 0) - throw new InvalidOperationException($"轴 {axis} 无法启动!当前设定速度为 0。"); + throw new InvalidOperationException($"轴 {轴编号} 无法启动!当前设定速度为 0。"); // 3. 检查动作轴使能,若为 false 则自动补写 true 激活驱动器 - bool isEnabled = await GetAxisEnableAsync(axis, ct); + bool isEnabled = await 查询轴使能(轴编号, 取消令牌); if (!isEnabled) { - await SetAxisEnableAsync(axis, true, ct); - await Task.Delay(100, ct); // 等待硬件继电器响应与伺服驱动就绪 + await 设置轴使能(轴编号, true, 取消令牌); + await Task.Delay(100, 取消令牌); // 等待硬件继电器响应与伺服驱动就绪 } // 4. 精准独立校验当前需要动作轴的目标定位是否越界 - int currentTarget = await GetAxisTargetPositionAsync(axis, ct); + int currentTarget = await 查询轴目标位置(轴编号, 取消令牌); int allowedMaxLimit = maxLimit - currentHomePos; if (currentTarget < 0 || currentTarget > allowedMaxLimit) { - throw new ArgumentOutOfRangeException($"轴 {axis} 无法启动!当前指定目标位置 [{currentTarget}] 超过了允许的最大安全极限值 [{allowedMaxLimit}]。"); + throw new ArgumentOutOfRangeException($"轴 {轴编号} 无法启动!当前指定目标位置 [{currentTarget}] 超过了允许的最大安全极限值 [{allowedMaxLimit}]。"); } // 5. 校验完成,边缘触发点动启动 - await TriggerCoilAsync(startAddress, ct); + await TriggerCoilAsync(startAddress, 取消令牌); } /// /// 三轴同时启动(全开:严格校验全部运行轴速度、批量检测与补正1~6号轴使能、联动校验三轴目标范围极限) /// - /// 取消令牌 - public async Task StartAllAxesAsync(CancellationToken ct = default) + /// 取消令牌 + public async Task 启动全部轴(CancellationToken 取消令牌 = default) { // 1. 一次性读取三轴速度,严禁任何一轴速度为 0 - int xSpeed = await GetAxisSpeedAsync(1, ct); - int ySpeed = await GetAxisSpeedAsync(2, ct); - int zSpeed = await GetAxisSpeedAsync(3, ct); + int xSpeed = await 查询轴速度(1, 取消令牌); + int ySpeed = await 查询轴速度(2, 取消令牌); + int zSpeed = await 查询轴速度(3, 取消令牌); if (xSpeed == 0 || ySpeed == 0 || zSpeed == 0) throw new InvalidOperationException($"无法全开启动!存在运行速度为 0 的轴。当前速度 -> X:{xSpeed}, Y:{ySpeed}, Z:{zSpeed}"); // 2. 批量读取 1 ~ 6 号轴连续的使能状态线圈,极大地优化网络性能 - bool[] enableStates = await ReadCoilsAsync(_slaveAddress, ADDR_HM_AXIS1_ENABLE, 6, ct); + bool[] enableStates = await ReadCoilsAsync(_slaveAddress, ADDR_HM_AXIS1_ENABLE, 6, 取消令牌); if (enableStates == null || enableStates.Length < 6) throw new InvalidOperationException("从 PLC 读取 1~6 号轴使能状态失败。"); @@ -439,21 +439,21 @@ namespace DeviceCommand.Devices { if (!enableStates[i]) { - await WriteSingleCoilAsync(_slaveAddress, enableAddresses[i], true, ct); + await WriteSingleCoilAsync(_slaveAddress, enableAddresses[i], true, 取消令牌); hasModifiedEnable = true; } } // 如果执行过使能补齐补齐写入,在循环外进行统一延时,保证PLC时序安全 if (hasModifiedEnable) - await Task.Delay(100, ct); + await Task.Delay(100, 取消令牌); // 3. 获取三轴原点及当前设定的目标指定位置 - var (xHome, yHome, zHome) = await GetHomePositionAsync(ct); + var (xHome, yHome, zHome) = await 查询原点位置(取消令牌); - int xTarget = await GetAxisTargetPositionAsync(1, ct); - int yTarget = await GetAxisTargetPositionAsync(2, ct); - int zTarget = await GetAxisTargetPositionAsync(3, ct); + int xTarget = await 查询轴目标位置(1, 取消令牌); + int yTarget = await 查询轴目标位置(2, 取消令牌); + int zTarget = await 查询轴目标位置(3, 取消令牌); // X轴安全范围联动校验 int xMaxAllowed = 50000 - xHome; @@ -471,15 +471,15 @@ namespace DeviceCommand.Devices throw new ArgumentOutOfRangeException(nameof(zTarget), $"Z轴目标位置 [{zTarget}] 越界,当前原点下最大范围 0-{zMaxAllowed}"); // 4. 全部联动校验通过,三轴点动同步启动 - await WriteSingleCoilAsync(_slaveAddress, ADDR_M_X_START, true, ct); - await WriteSingleCoilAsync(_slaveAddress, ADDR_M_Y_START, true, ct); - await WriteSingleCoilAsync(_slaveAddress, ADDR_M_Z_START, true, ct); + await WriteSingleCoilAsync(_slaveAddress, ADDR_M_X_START, true, 取消令牌); + await WriteSingleCoilAsync(_slaveAddress, ADDR_M_Y_START, true, 取消令牌); + await WriteSingleCoilAsync(_slaveAddress, ADDR_M_Z_START, true, 取消令牌); - await Task.Delay(100, ct); // 保持高电平状态以适配 PLC 扫描周期 + await Task.Delay(100, 取消令牌); // 保持高电平状态以适配 PLC 扫描周期 - await WriteSingleCoilAsync(_slaveAddress, ADDR_M_X_START, false, ct); - await WriteSingleCoilAsync(_slaveAddress, ADDR_M_Y_START, false, ct); - await WriteSingleCoilAsync(_slaveAddress, ADDR_M_Z_START, false, ct); + await WriteSingleCoilAsync(_slaveAddress, ADDR_M_X_START, false, 取消令牌); + await WriteSingleCoilAsync(_slaveAddress, ADDR_M_Y_START, false, 取消令牌); + await WriteSingleCoilAsync(_slaveAddress, ADDR_M_Z_START, false, 取消令牌); } #region 内部高低字工具转化方法 @@ -521,12 +521,12 @@ namespace DeviceCommand.Devices /// /// 读取指定轴的绝对位置(相对原点的实时位置,只读) /// - /// 轴编号 (1-6) - /// 取消令牌 + /// 轴编号 (1-6) + /// 取消令牌 /// 指定轴的绝对位置值 - public async Task GetAbsolutePositionAsync(int axis, CancellationToken ct = default) + public async Task 查询轴绝对位置(int 轴编号, CancellationToken 取消令牌 = default) { - ushort address = axis switch + ushort address = 轴编号 switch { 1 => ADDR_ABS_AXIS1_POS, 2 => ADDR_ABS_AXIS2_POS, @@ -534,12 +534,12 @@ namespace DeviceCommand.Devices 4 => ADDR_ABS_AXIS4_POS, 5 => ADDR_ABS_AXIS5_POS, 6 => ADDR_ABS_AXIS6_POS, - _ => throw new ArgumentException("轴编号错误,仅支持 1-6", nameof(axis)) + _ => throw new ArgumentException("轴编号错误,仅支持 1-6", nameof(轴编号)) }; - ushort[] registers = await ReadHoldingRegistersAsync(_slaveAddress, address, 2, ct); + ushort[] registers = await ReadHoldingRegistersAsync(_slaveAddress, address, 2, 取消令牌); if (registers == null || registers.Length < 2) - throw new InvalidOperationException($"读取轴 {axis} 绝对位置失败。"); + throw new InvalidOperationException($"读取轴 {轴编号} 绝对位置失败。"); return UshortsToInt32(registers); } @@ -547,12 +547,12 @@ namespace DeviceCommand.Devices /// /// 批量读取 1-6 轴的绝对位置(一次性读取 22 个寄存器,高效) /// - /// 取消令牌 + /// 取消令牌 /// 返回 6 轴绝对位置元组 - public async Task<(int Axis1, int Axis2, int Axis3, int Axis4, int Axis5, int Axis6)> GetAllAbsolutePositionsAsync(CancellationToken ct = default) + public async Task<(int Axis1, int Axis2, int Axis3, int Axis4, int Axis5, int Axis6)> 查询全部轴绝对位置(CancellationToken 取消令牌 = default) { // 从 47232 开始连续读取 22 个寄存器(覆盖 47232-47253) - ushort[] registers = await ReadHoldingRegistersAsync(_slaveAddress, ADDR_ABS_AXIS1_POS, 22, ct); + ushort[] registers = await ReadHoldingRegistersAsync(_slaveAddress, ADDR_ABS_AXIS1_POS, 22, 取消令牌); if (registers == null || registers.Length < 22) throw new InvalidOperationException("批量读取 6 轴绝对位置失败,返回数据长度不足。"); diff --git a/ZLGUSBCANFD/USBCANFD.cs b/ZLGUSBCANFD/USBCANFD.cs index ac0a75a..be70fe9 100644 --- a/ZLGUSBCANFD/USBCANFD.cs +++ b/ZLGUSBCANFD/USBCANFD.cs @@ -56,6 +56,12 @@ namespace ZLGUSBCANFD /// public event Action? OnDbcMessageDecoded; + /// + /// 事件:当接收到任意 CAN/CANFD 原始报文时触发(不依赖 DBC,自定义报文也能收到) + /// 参数:通道号, 帧ID, 数据, 时间戳(微秒), 是否FD, 数据长度 + /// + public event Action? OnRawMessageReceived; + public ZLGCANFD(uint deviceType = 76, uint deviceIndex = 0, int maxChannels = 4, string abitBaud = "500000", string dbitBaud = "2000000", bool enableTerminalResistance = true) { @@ -297,6 +303,10 @@ namespace ZLGUSBCANFD { IntPtr framePtr = IntPtr.Add(ptrCanBuffer, i * canStructSize); + // 触发原始报文事件(不依赖 DBC,自定义报文也能收到) + var rawData = (ZLGCAN.ZCAN_Receive_Data)Marshal.PtrToStructure(framePtr, typeof(ZLGCAN.ZCAN_Receive_Data))!; + OnRawMessageReceived?.Invoke(channelIndex, rawData.frame.can_id, rawData.frame.data, rawData.timestamp, false, rawData.frame.can_dlc); + // 只锁定当前通道的DBC句柄进行解码,高并发完全不卡顿 lock (_channelLocks[channelIndex]) { @@ -319,6 +329,10 @@ namespace ZLGUSBCANFD { IntPtr framePtr = IntPtr.Add(ptrCanFDBuffer, i * canfdStructSize); + // 触发原始报文事件(不依赖 DBC,自定义报文也能收到) + var rawFdData = (ZLGCAN.ZCAN_ReceiveFD_Data)Marshal.PtrToStructure(framePtr, typeof(ZLGCAN.ZCAN_ReceiveFD_Data))!; + OnRawMessageReceived?.Invoke(channelIndex, rawFdData.frame.can_id, rawFdData.frame.data, rawFdData.timestamp, true, rawFdData.frame.len); + lock (_channelLocks[channelIndex]) { if (_isDbcLoadedArray[channelIndex] && ZDBC.ZDBC_Decode(_dbcHandles[channelIndex], ptrDbcMsg, framePtr, 1, 1))