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)
|
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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user