This commit is contained in:
“hsc”
2026-10-13 13:41:05 +08:00
parent d84f2a874b
commit 691fb62385
2 changed files with 60 additions and 8 deletions
+53 -1
View File
@@ -195,13 +195,21 @@ namespace DeviceCommand.Base
} }
} }
/// <summary>
/// 读取定长原始二进制字节(用于 IT6720 等自定义二进制帧协议)。
/// <para>VISA 会话在 <see cref="ResetConnection"/> 中默认启用了以 <c>\n</c>(0x0A) 为终止符的文本读取;
/// 而二进制帧的数据区可能恰好包含 0x0A 字节,若不禁用终止符,<c>RawIO.Read</c> 会在该字节处提前结束,
/// 导致返回长度不足、帧校验失败。故本方法读取期间临时关闭终止符,读完再由 finally 恢复。</para>
/// <para>单次 <c>RawIO.Read(count)</c> 只保证返回「至多 count」字节,可能因分包而少于请求长度;
/// 这里参照 <see cref="ReadRawUntilEnd"/> 的做法循环补足,直到读满 length 或发生超时/END/流终止。</para>
/// </summary>
public async Task<byte[]> ReadAsync(int length, CancellationToken ct = default) public async Task<byte[]> ReadAsync(int length, CancellationToken ct = default)
{ {
await _commLock.WaitAsync(ct); await _commLock.WaitAsync(ct);
try try
{ {
EnsureConnected(); EnsureConnected();
return await Task.Run(() => _session!.RawIO.Read(length), ct); return await Task.Run(() => ReadExactBytes(length), ct);
} }
finally finally
{ {
@@ -209,6 +217,50 @@ namespace DeviceCommand.Base
} }
} }
/// <summary>
/// 同步读取定长二进制字节:关闭终止符后循环补足,直到读满 <paramref name="length"/> 字节;
/// 超时/END/流终止导致读不满时按实到长度截断返回(由上层按帧长校验判定成功与否)。
/// </summary>
private byte[] ReadExactBytes(int length)
{
if (length <= 0) return Array.Empty<byte>();
bool prevTermEnabled = _session!.TerminationCharacterEnabled;
// 二进制帧数据可能含 0x0A,读取全程禁用终止符,避免被误判为帧结束而截断
_session!.TerminationCharacterEnabled = false;
try
{
var buffer = new byte[length];
int offset = 0;
while (offset < length)
{
byte[] chunk;
try
{
chunk = _session!.RawIO.Read(length - offset);
}
catch (Exception) when (offset > 0)
{
// 已收到部分数据后再超时/异常:返回已收字节,交由上层按帧长校验处理
break;
}
if (chunk == null || chunk.Length == 0) break;
Buffer.BlockCopy(chunk, 0, buffer, offset, chunk.Length);
offset += chunk.Length;
}
if (offset == length) return buffer;
// 实际读到的字节少于请求长度:按实到长度截断返回,避免尾部填充 0
var trimmed = new byte[offset];
Buffer.BlockCopy(buffer, 0, trimmed, 0, offset);
return trimmed;
}
finally
{
_session!.TerminationCharacterEnabled = prevTermEnabled;
}
}
public async Task<string> ReadAsync(string delimiter = "\n", CancellationToken ct = default) public async Task<string> ReadAsync(string delimiter = "\n", CancellationToken ct = default)
{ {
await _commLock.WaitAsync(ct); await _commLock.WaitAsync(ct);
+7 -7
View File
@@ -13,14 +13,14 @@ namespace DeviceCommand.Devices
/// 低压电源 一拖三 /// 低压电源 一拖三
/// </summary> /// </summary>
[ACPCommand] [ACPCommand]
public class IT6720: Serial_Port // 直接继承您提供的 Serial_Port 基类 public class IT6720 : Visa // 继承 VISA 基类(USB VISA 资源字符串寻址,如 USB0::VID::PID::SN::INSTR)
{ {
// 帧格式:同步头 AA + 地址 + 命令字 + 数据[4-25] + 校验和,共 26 字节 // 帧格式:同步头 AA + 地址 + 命令字 + 数据[4-25] + 校验和,共 26 字节
private const byte FrameSyncByte = 0xAA; private const byte FrameSyncByte = 0xAA;
private const int FrameLength = 26; private const int FrameLength = 26;
private readonly byte _deviceAddress = 0x00; // 电源地址 private readonly byte _deviceAddress = 0x00; // 电源地址
public IT6720(SerialPortConfig config) : base(config) public IT6720(VisaConfig config) : base(config)
{ {
} }
@@ -109,12 +109,12 @@ namespace DeviceCommand.Devices
{ {
byte[] sendFrame = BuildFrame(command, dataBytes); byte[] sendFrame = BuildFrame(command, dataBytes);
// 使用基类提供的 WriteBytesAsync 发送二进制数据 // 使用基类提供的 SendAsync(byte[]) 通过 VISA 会话发送二进制数据帧
await WriteBytesAsync(sendFrame, ct).ConfigureAwait(false); await SendAsync(sendFrame, ct).ConfigureAwait(false);
// 使用基类提供的 ReadBytesAsync 读取定长 26 字节二进制数据 // 使用基类提供的 ReadAsync(int) 读取定长 26 字节二进制数据帧
// 注意:这里的 ReadTimeout 由基类统一控制 // 注意:读写超时(IOTimeout)与终止符处理均由 VISA 基类统一控制
return await ReadBytesAsync(FrameLength, ct).ConfigureAwait(false); return await ReadAsync(FrameLength, ct).ConfigureAwait(false);
} }
#endregion #endregion