visa
This commit is contained in:
@@ -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)
|
||||
{
|
||||
await _commLock.WaitAsync(ct);
|
||||
try
|
||||
{
|
||||
EnsureConnected();
|
||||
return await Task.Run(() => _session!.RawIO.Read(length), ct);
|
||||
return await Task.Run(() => ReadExactBytes(length), ct);
|
||||
}
|
||||
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)
|
||||
{
|
||||
await _commLock.WaitAsync(ct);
|
||||
|
||||
@@ -13,14 +13,14 @@ namespace DeviceCommand.Devices
|
||||
/// 低压电源 一拖三
|
||||
/// </summary>
|
||||
[ACPCommand]
|
||||
public class IT6720: Serial_Port // 直接继承您提供的 Serial_Port 基类
|
||||
public class IT6720 : Visa // 继承 VISA 基类(USB VISA 资源字符串寻址,如 USB0::VID::PID::SN::INSTR)
|
||||
{
|
||||
// 帧格式:同步头 AA + 地址 + 命令字 + 数据[4-25] + 校验和,共 26 字节
|
||||
private const byte FrameSyncByte = 0xAA;
|
||||
private const int FrameLength = 26;
|
||||
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);
|
||||
|
||||
// 使用基类提供的 WriteBytesAsync 发送二进制数据
|
||||
await WriteBytesAsync(sendFrame, ct).ConfigureAwait(false);
|
||||
// 使用基类提供的 SendAsync(byte[]) 通过 VISA 会话发送二进制数据帧
|
||||
await SendAsync(sendFrame, ct).ConfigureAwait(false);
|
||||
|
||||
// 使用基类提供的 ReadBytesAsync 读取定长 26 字节二进制数据
|
||||
// 注意:这里的 ReadTimeout 由基类统一控制
|
||||
return await ReadBytesAsync(FrameLength, ct).ConfigureAwait(false);
|
||||
// 使用基类提供的 ReadAsync(int) 读取定长 26 字节二进制数据帧
|
||||
// 注意:读写超时(IOTimeout)与终止符处理均由 VISA 基类统一控制
|
||||
return await ReadAsync(FrameLength, ct).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
Reference in New Issue
Block a user